With Wan-hsuan, starting from 2023 Oct

[1] Experimental protocols

[1.1] Sampling locations and dates

[1.1.1] Locations

  1. Stn.Ie-1 in the north basin of Lake Biwa: Ie-1 35°12’58”N 135°59’55”E
  2. Yasu river: 35°02’35.5”N 136°01’10.0”E
  3. Hino river: 35°06’09.1”N 136°04’37.4”E
  4. Echi river: 35°11’44.0”N 136°10’46.5”E
  5. Ane river: 35°24’45.1”N 136°16’59.0”E
[1.1.2] Dates
  1. Lake Biwa: 2019/07/03, 07/30, 09/10, 10/17
  2. Four rivers: 2019/07/09, 08/07, 09/17, 10/15

[1.2] Sampling methods

[1.2.1] Collection of prokaryotic DNA: Filtering Water

  • STERIVEX-GV 0.22UM PVDF

[1.3] 1st and 2nd PCR

[1.3.1] Primers

C:_R_from2019\1st_2nd_PCR_v106_hts_tube_jp_orderform20191204.xls Eurofins (515F, 806R) ### [1.5] Miseq sequence (Run ID: RMR152)

[2] Bioinformatics/modeling protocols

[2.0] Generating Fastq files without demultiplexing (bcl2fastq v2.18)

[2.1] Tag and Primer Filtering and Demultiplex by claident (version v0.2.2018.05.29)

[2.2] dada2 for ASV composition

[2.3] PiCRUSt2 for KO composition for each ASV

[3] Loading and summarizing data

[3.0] Loading packages & setting random seed

library(vegan)
Loading required package: permute
Loading required package: lattice
This is vegan 2.6-4
library(ggeffects)
library(ggplot2)
library(parallel)
set.seed(1234567)

[3.1] Loading data

[3.1.1] Loading sample information for Miseq

sample_info <- read.csv("SampleSheet_RMR152.csv", skip = 19, header = T)
sample_info

[3.1.2] Bacterial direct count

#loading data
raw_bac_count <- read.csv("bacterial_count_sumitomo.csv", header = T)
raw_bac_count
#calculating the averages of ten repetitions for each example
average <- apply(raw_bac_count[3:12], 1, mean)
#converting the averaged raw count to cell density (cells/mL) using conversion factors
A <- 210 #effective filtered area (mm^2)
G <- 77*77*1.0e-6 #area of one vision (mm^2)
V <- 1.0  #volume of filtered sample (ml)
cell_density <- average*(A/G)/V
#integrating into the dataframe
bac_cell_density <- data.frame(month = raw_bac_count$month, location = raw_bac_count$river, average_count = average, density = cell_density)
bac_cell_density
saveRDS(bac_cell_density, "bac_cell_density.obj")

[3.1.3] Ecoplate-based Multifunctionality = Phenotypic Multifunctionality (MF_P)

MF_P <- readRDS("./Jan2024v3/MF_list/MF_integ14_ave_matrix_raw.obj")
head(MF_P)
              Sample_1 Sample_2 Sample_3 Sample_4 Sample_5 Sample_6 Sample_7 Sample_8 Sample_9
treshold_0          21       29       30       30       30       15       31       30       30
treshold_0.05       18       29       29       30       30       10       31       30       30
treshold_0.1        17       29       29       30       29        8       31       30       30
treshold_0.15       16       29       28       30       29        5       31       28       30
treshold_0.2        16       29       28       29       29        4       29       28       30
treshold_0.25       13       29       27       29       29        2       28       27       30
              Sample_10 Sample_11 Sample_12 Sample_13 Sample_14 Sample_15 Sample_16 Sample_17
treshold_0           28        22        30        31        30        29        30        30
treshold_0.05        28        13        30        30        29        27        30        30
treshold_0.1         26        10        30        30        29        27        30        30
treshold_0.15        26         5        30        30        28        26        30        30
treshold_0.2         26         3        30        29        28        21        28        30
treshold_0.25        24         2        30        29        28        17        25        30
              Sample_18 Sample_19 Sample_20
treshold_0           28        30        30
treshold_0.05        28        30        30
treshold_0.1         28        30        30
treshold_0.15        28        30        30
treshold_0.2         28        30        30
treshold_0.25        28        30        30

[3.1.4] Compiled sample info, before coverage-based standardization

List of ASV composition before coverage-based standardization but ASVs from mitochondria and chloroplas excluded

raw_prokaryote_ASVcomposition_info <- as.data.frame( readRDS("./Jan2024v3/ASV_composition/table_ASV_no-mitochondria-no-chloroplas_biwako_dada2_Jan2024.obj"))

#The number of ASVs that were detected in two negative samples
apply(raw_prokaryote_ASVcomposition_info > 0, 1, sum)[21:22]
s021_prokaryote.forward.fastq s022_prokaryote.forward.fastq 
                           12                             7 
#The total reads that were detected in two negative samples
apply(raw_prokaryote_ASVcomposition_info, 1, sum)[21:22]
s021_prokaryote.forward.fastq s022_prokaryote.forward.fastq 
                           29                            16 

List of sample (data set) info, bacterial abundance, sampling coverage (cov_exclu), #reads (seq_exclu), #observed ASVs (rich_exclu)

attributes_sample <- readRDS("./Jan2024v3/attri_exclu_undeter.eukar_Jan2024.obj")
attributes_sample$sample_ID <- c("S01", "S02", "S03", "S04", "S05", "S06", "S07", "S08", "S09", "S10", "S11", "S12", "S13", "S14", "S15", "S16", "S17", "S18", "S19", "S20")
attributes_sample[, -c(4,5)] 

[3.1.5] ASV composition table

ASV table being rarefied with the coverage = 0.9232 and then ASVs with 1) poor alignment to PiCRUST2 or 2) with 0 abundance being deleted, noting that the data sets with low coverages were also excluded and 13 data sets remained.

remaining_ID <- c("S01", "S02", "S03", "S04", "S05", "S06", "S07", "S08", "S11", "S17", "S18", "S19", "S20")
stand_ASV_com <- readRDS("./Jan2024v3/ASV_composition/Com_rarefied_exclu_undeter.eukar_AfterNeg_filtered_order_del0ASV_Jan2024.obj")
class(stand_ASV_com)
[1] "data.frame"
colnames(stand_ASV_com)
 [1] "Sample_1"  "Sample_2"  "Sample_3"  "Sample_4"  "Sample_5"  "Sample_6"  "Sample_7" 
 [8] "Sample_8"  "Sample_11" "Sample_17" "Sample_18" "Sample_19" "Sample_20"
colnames(stand_ASV_com) <- remaining_ID
head(stand_ASV_com[, 2:5])

[3.1.6] KO composition table for each ASV that was included in “stand_ASV_com”.

KO_com <- readRDS("./Jan2024v3/KO_composition/KO_exclu_undeter.eukar_AfterNeg_filtered_order_del0ASV_Jan2024.obj")
class(KO_com)
[1] "data.frame"
head(KO_com)

[3.2] Data conversion

[3.2.1] Binarization

Binarization of ASV composition with the threshold 0.0 for ASVs and 1 for KOs

#copy
stand_ASV_com_binarized <- stand_ASV_com
KO_com_binarized <- KO_com

#binarized
stand_ASV_com_binarized[stand_ASV_com_binarized > 0] <- 1.0
stand_ASV_com_binarized[stand_ASV_com_binarized < 0] <- 0.0

KO_com_binarized[KO_com_binarized >= 1.0] <- 1.0
KO_com_binarized[KO_com_binarized < 1.0] <- 0.0

[3.2.2] Calculating richness

ASV and KO richness for the whole dat sets

ASV_gamma_richness <- sum(apply(stand_ASV_com_binarized, 1, sum) > 0)
KO_gamma_richness <- sum(apply(KO_com_binarized, 2, sum) > 0)
ASV_gamma_richness
[1] 3576
KO_gamma_richness
[1] 7340

ASV and KO richness for each data set

stand_ASV_richness <- apply(stand_ASV_com_binarized, 2, sum)
KO_richness <- numeric(13)
for(j in 1:13) {
  #Obtain the KO composition for each data set
  KO_list <- t(KO_com_binarized) %*% stand_ASV_com_binarized[, j]
  #Calculate the number of KOs
  KO_richness[j] <- sum(KO_list > 0)
}
MF_P_filtered0.05 <- MF_P[2, c(1,2,3,4,5,6,7,8,11,17,18,19,20)] #subsets of samples that are remaining for further bioinformatic analyses
plot(stand_ASV_richness, KO_richness)

plot(stand_ASV_richness, MF_P_filtered0.05)

[3.3] Summary of data sets

Summarizing basic info into a dataframe

richness_temp <- data.frame(sample_ID = remaining_ID, stand_ASV_richness, KO_richness)
data_summary <- merge(attributes_sample[, -c(4,5)], richness_temp, by = "sample_ID", all = T)
colnames(data_summary)[4:7] <- c("bacterial abundance", "coverage", "no_reads", "obs_ASV_richness")
data_summary <- data.frame(data_summary, MF_P0.05 = MF_P[2, ])
data_summary

[4] Relationship between ASV richness, KO richness, and Ecoplate Multifunctionality

[4.1] Data prearrangement

richness_MF <- data.frame(ASV_richness = stand_ASV_richness, MF_G = KO_richness, MF_P0.05 = MF_P_filtered0.05, location = data_summary$location[c(1,2,3,4,5,6,7,8,11,17,18,19,20)], date = data_summary$date_sample[c(1,2,3,4,5,6,7,8,11,17,18,19,20)])
                                                                                                                    
richness_MF

[4.2] Basic plotting

plot(richness_MF)

[4.3] linear model

lm_model <- lm(MF_P0.05 ~ MF_G, data = richness_MF)
summary(lm_model)

Call:
lm(formula = MF_P0.05 ~ MF_G, data = richness_MF)

Residuals:
    Min      1Q  Median      3Q     Max 
-9.4562 -0.9701  0.9245  1.3430  4.7861 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -39.208828   9.942854  -3.943   0.0023 ** 
MF_G          0.009584   0.001455   6.588 3.93e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.408 on 11 degrees of freedom
Multiple R-squared:  0.7978,    Adjusted R-squared:  0.7794 
F-statistic:  43.4 on 1 and 11 DF,  p-value: 3.926e-05
plot(MF_P0.05 ~ MF_G, data = richness_MF)
abline(lm_model)


#glm and stepwise model selection
summary(step(glm(MF_P0.05 ~ MF_G + ASV_richness, data = richness_MF, family = poisson(link = "log"))))
Start:  AIC=77.07
MF_P0.05 ~ MF_G + ASV_richness

               Df Deviance    AIC
- ASV_richness  1   5.5179 75.171
<none>              5.4150 77.068
- MF_G          1  10.0893 79.742

Step:  AIC=75.17
MF_P0.05 ~ MF_G

       Df Deviance    AIC
<none>      5.5179 75.171
- MF_G  1  28.8685 96.522

Call:
glm(formula = MF_P0.05 ~ MF_G, family = poisson(link = "log"), 
    data = richness_MF)

Deviance Residuals: 
     Min        1Q    Median        3Q       Max  
-2.00659  -0.01277   0.07949   0.26200   0.93343  

Coefficients:
              Estimate Std. Error z value Pr(>|z|)    
(Intercept) -0.1612495  0.8031090  -0.201    0.841    
MF_G         0.0004963  0.0001151   4.311 1.63e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for poisson family taken to be 1)

    Null deviance: 28.8685  on 12  degrees of freedom
Residual deviance:  5.5179  on 11  degrees of freedom
AIC: 75.171

Number of Fisher Scoring iterations: 4
#best
z <- glm(MF_P0.05 ~ MF_G, data = richness_MF, family = poisson(link = "log"))

[4.3.1] Figure 1


y_max <- 35
richness_MF$mf_g = seq(4500, 7300, length.out = 13)
richness_MF$predicted = exp(z$coefficients[1] + z$coefficients[2] * richness_MF$mf_g)
richness_MF$Low = richness_MF$predicted - 2 * sqrt(mean(richness_MF$MF_P0.05))
richness_MF$Low[richness_MF$Low < 0] <- 0
richness_MF$High = richness_MF$predicted + 2 * sqrt(mean(richness_MF$MF_P0.05))
richness_MF$High[richness_MF$High > y_max] <- y_max

linear_plot <- ggplot(data = richness_MF) + geom_point(aes(x = MF_G, y = MF_P0.05, shape = richness_MF$location), size = 3, alpha = 0.9) + labs(shape = "sites") + scale_shape_manual(values = c(0, 1, 2, 5, 6)) 
linear_plot <- linear_plot + geom_line(aes(x = mf_g, y = predicted))
linear_plot <- linear_plot + geom_ribbon(aes(x = mf_g, ymin = Low, ymax = High), alpha = 0.1)
linear_plot <- linear_plot + xlab("MF_G") + ylab("MF_P") + ylim(0, y_max) + theme_bw() 
plot(linear_plot)

Save it as the pdf file

pdf("figure01.pdf", width = 10, height = 7, onefile = FALSE)
plot(linear_plot)
# Close the PostScript device
dev.off()
null device 
          1 

[4.3.2] Statistical test when S11 data is excluded

#glm and stepwise model selection
summary(step(glm(MF_P0.05 ~ MF_G + ASV_richness, data = richness_MF[-9, ], family = poisson(link = "log"))))
Start:  AIC=70.23
MF_P0.05 ~ MF_G + ASV_richness

               Df Deviance    AIC
- ASV_richness  1   3.3491 68.587
<none>              2.9914 70.229
- MF_G          1   9.3325 74.570

Step:  AIC=68.59
MF_P0.05 ~ MF_G

       Df Deviance    AIC
<none>      3.3491 68.587
- MF_G  1  20.3561 83.594

Call:
glm(formula = MF_P0.05 ~ MF_G, family = poisson(link = "log"), 
    data = richness_MF[-9, ])

Deviance Residuals: 
     Min        1Q    Median        3Q       Max  
-1.27975  -0.21120   0.09244   0.27598   0.88318  

Coefficients:
              Estimate Std. Error z value Pr(>|z|)    
(Intercept) -1.6039451  1.3093124  -1.225 0.220564    
MF_G         0.0007002  0.0001858   3.768 0.000165 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for poisson family taken to be 1)

    Null deviance: 20.3561  on 11  degrees of freedom
Residual deviance:  3.3491  on 10  degrees of freedom
AIC: 68.587

Number of Fisher Scoring iterations: 4

[5] Simulations for ASV extinction

[5.1] Random extinction (analytical formulation)

Ref: COLWELL et al. Ecology, 85(10), 2004, pp. 2717-2727

Q: How many species have each KO?

A: Inner product of the transposed KO table and ASV vector of the specific sample returns the vector regarding how many species have each KO

[5.1.1] Definition of functions for interporation

Note: n! = gamma(n+1) but it cannot be directly used

alpha_jh <- function(j, h, H) {
  temp <- 0.0
  if(j + h > H) {
    temp <- 0.0
  } else {
    temp <- 1.0
    for(k in 0:(h - 1)) temp <- temp*(H - j - k)/(H - k)
  }
  return(temp)
}

tau_chir <- function(h, S_obs, H, s){
  temp <- S_obs
  for (j in 1:H) temp <- temp - alpha_jh(j, h, H)*s[j];
  return(temp)
}

[5.1.2] Trial for a single sample (S02)

#Example for a single sample
KO_dist <- t(KO_com_binarized) %*% stand_ASV_com_binarized$S02
hist(KO_dist)

Index for interporation function

s <- vector() #number of KOs with j time appearance
for(j in 1:max(KO_dist)) {
  s[j] <- sum(KO_dist == j)
}

Trial of interporation (random extinction)

tau <- vector()
ASV_richness_02 <- data_summary$stand_ASV_richness[2]
KO_richness_02 <- data_summary$KO_richness[2]
for(x in 1:ASV_richness_02) tau[x] <- tau_chir(x, KO_richness_02, ASV_richness_02, s)
plot(1:ASV_richness_02, tau)

plot(log10(1:ASV_richness_02), log10(tau))

Fitting power-law regression with difference ranges and interval

x <- 1:ASV_richness_02
#full range of ASV richness and the fine interval 
summary(fit_full <- lm(formula = log10(tau) ~ log10(x)))

Call:
lm(formula = log10(tau) ~ log10(x))

Residuals:
     Min       1Q   Median       3Q      Max 
-0.38874 -0.00900  0.00023  0.01135  0.01975 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 3.4551158  0.0025479  1356.1   <2e-16 ***
log10(x)    0.1230978  0.0008476   145.2   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.01849 on 2558 degrees of freedom
Multiple R-squared:  0.8918,    Adjusted R-squared:  0.8918 
F-statistic: 2.109e+04 on 1 and 2558 DF,  p-value: < 2.2e-16
#For the coarse interval (every 5 %)
s <- ASV_richness_02/20
no_ASV <- vector()
no_ASV[1] <- 1
for(k in 2:20) no_ASV[k] <- round(s*(k - 1))
no_ASV[21] <- ASV_richness_02

#full range and coarse interval
summary(fit_full_c <- lm(formula = log10(tau[no_ASV]) ~ log10(x[no_ASV])))

Call:
lm(formula = log10(tau[no_ASV]) ~ log10(x[no_ASV]))

Residuals:
      Min        1Q    Median        3Q       Max 
-0.097240 -0.033375 -0.008542  0.028329  0.102984 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)       3.16362    0.04445   71.18  < 2e-16 ***
log10(x[no_ASV])  0.21822    0.01495   14.60  8.9e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.04979 on 19 degrees of freedom
Multiple R-squared:  0.9181,    Adjusted R-squared:  0.9138 
F-statistic:   213 on 1 and 19 DF,  p-value: 8.901e-12
#0-50% reduction range and the fine interval
summary(fit_50 <- lm(formula = log10(tau[no_ASV[11]:ASV_richness_02]) ~ log10(x[no_ASV[11]:ASV_richness_02])))

Call:
lm(formula = log10(tau[no_ASV[11]:ASV_richness_02]) ~ log10(x[no_ASV[11]:ASV_richness_02]))

Residuals:
       Min         1Q     Median         3Q        Max 
-5.130e-04 -1.526e-04  5.609e-05  1.821e-04  2.243e-04 

Coefficients:
                                      Estimate Std. Error t value Pr(>|t|)    
(Intercept)                          3.642e+00  2.145e-04 16981.8   <2e-16 ***
log10(x[no_ASV[11]:ASV_richness_02]) 6.351e-02  6.547e-05   970.1   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.0002014 on 1279 degrees of freedom
Multiple R-squared:  0.9986,    Adjusted R-squared:  0.9986 
F-statistic: 9.41e+05 on 1 and 1279 DF,  p-value: < 2.2e-16
#0-50% reduction range and the coarse interval
summary(fit_50_c <- lm(formula = log10(tau[no_ASV[11:21]]) ~ log10(no_ASV[11:21])))

Call:
lm(formula = log10(tau[no_ASV[11:21]]) ~ log10(no_ASV[11:21]))

Residuals:
       Min         1Q     Median         3Q        Max 
-0.0004339 -0.0001518  0.0001014  0.0002110  0.0002695 

Coefficients:
                      Estimate Std. Error t value Pr(>|t|)    
(Intercept)          3.6416629  0.0027765 1311.60  < 2e-16 ***
log10(no_ASV[11:21]) 0.0637098  0.0008479   75.14 6.63e-14 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.0002659 on 9 degrees of freedom
Multiple R-squared:  0.9984,    Adjusted R-squared:  0.9982 
F-statistic:  5646 on 1 and 9 DF,  p-value: 6.626e-14
#0-90% reduction range and the fine interval
summary(fit_10 <- lm(formula = log10(tau[no_ASV[3]:ASV_richness_02]) ~ log10(x[no_ASV[3]:ASV_richness_02])))

Call:
lm(formula = log10(tau[no_ASV[3]:ASV_richness_02]) ~ log10(x[no_ASV[3]:ASV_richness_02]))

Residuals:
       Min         1Q     Median         3Q        Max 
-0.0095432 -0.0014807  0.0004911  0.0019216  0.0024601 

Coefficients:
                                     Estimate Std. Error t value Pr(>|t|)    
(Intercept)                         3.5855191  0.0005641  6355.8   <2e-16 ***
log10(x[no_ASV[3]:ASV_richness_02]) 0.0810340  0.0001822   444.7   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.002235 on 2303 degrees of freedom
Multiple R-squared:  0.9885,    Adjusted R-squared:  0.9885 
F-statistic: 1.977e+05 on 1 and 2303 DF,  p-value: < 2.2e-16
#0-90% reduction range and the coarse interval
summary(fit_10_c <- lm(formula = log10(tau[no_ASV[3:21]]) ~ log10(no_ASV[3:21])))

Call:
lm(formula = log10(tau[no_ASV[3:21]]) ~ log10(no_ASV[3:21]))

Residuals:
       Min         1Q     Median         3Q        Max 
-0.0076597 -0.0015030  0.0006151  0.0023998  0.0031114 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)         3.578215   0.007448  480.46   <2e-16 ***
log10(no_ASV[3:21]) 0.083285   0.002412   34.53   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.002932 on 17 degrees of freedom
Multiple R-squared:  0.9859,    Adjusted R-squared:  0.9851 
F-statistic:  1192 on 1 and 17 DF,  p-value: < 2.2e-16
plot(log10(tau) ~ log10(1:ASV_richness_02), 
     xlim = c(0, log10(ASV_richness_02)), 
     ylim = c(2, max(log10(tau))),
     xlab = "Log10(ASV richness)", 
     ylab = "Log10(KO richness)",
     main = "Ane river 20190709"
     )
abline(fit_full, col = 2, lwd = 2)
abline(fit_10, col = 3, lwd = 2)
abline(fit_50, col = 4, lwd = 2)
abline(fit_full_c, col = 1, lty = "dashed")
abline(fit_10_c, col = 1, lty = "dashed")
abline(fit_50_c, col = 1, lty = "dashed")
abline(v = log10(no_ASV[3]), col = 3, lty = "dashed", lwd = 2)
abline(v = log10(no_ASV[11]), col = 4, lty = "dashed", lwd = 2)


fitted_model <- function(x) {
  temp <- (10^fit_full$coefficients[1])*(x^fit_full$coefficients[2])
  return(temp)
} 
plot(1:ASV_richness_02, tau, xlim = c(1, ASV_richness_02), ylim = c(0, max(tau)))
par(new = T)
plot(1:ASV_richness_02, fitted_model(x), xlim = c(1, ASV_richness_02), ylim = c(0, max(tau)), xlab = "", ylab = "", col = 4, type = "l")

[5.1.3] For all samples together

Definition of function, which has the binarized ASV composition and the binarized KO table as parameters

sample_ID <- c(1, 2, 3, 4, 5, 6, 7, 8, 11, 17, 18, 19, 20) #only a part of samples is used
random_extinction <- function(com_binarized, KO_binarized) {
  ASV_richness <- vector()
  KO_richness <- vector()
  tau_one <- vector() #expected KO richness with a single ASV
  slope_full <- vector() #slope of fitted power law
  slope_full_c <- vector() #slope of fitted power law
  slope_50 <- vector() #slope of fitted power law
  slope_50_c <- vector() #slope of fitted power law
  slope_10 <- vector() #slope of fitted power law
  slope_10_c <- vector() #slope of fitted power law
  
  slope_full_up <- vector() #upper limit of 95% confidence interval
  slope_full_down <- vector() #lower limit of 95% confidence interval
  slope_full_c_up <- vector() #upper limit of 95% confidence interval
  slope_full_c_down <- vector() #lower limit of 95% confidence interval
  slope_50_up <- vector() #upper limit of 95% confidence interval
  slope_50_down <- vector() #lower limit of 95% confidence interval
  slope_50_c_up <- vector() #upper limit of 95% confidence interval
  slope_50_c_down <- vector() #lower limit of 95% confidence interval
  slope_10_up <- vector() #upper limit of 95% confidence interval
  slope_10_down <- vector() #lower limit of 95% confidence interval
  slope_10_c_up <- vector() #upper limit of 95% confidence interval
  slope_10_c_down <- vector() #lower limit of 95% confidence interval

  intercept_full <- vector() #intercept of fitted power law 
  intercept_full_c <- vector() #intercept of fitted power law 
  intercept_50 <- vector() #intercept of fitted power law 
  intercept_50_c <- vector() #intercept of fitted power law 
  intercept_10 <- vector() #intercept of fitted power law 
  intercept_10_c <- vector() #intercept of fitted power law 
  
  R2fitted_full <- vector() #adjusted R-squared value of fitted power law
  R2fitted_full_c <- vector() #adjusted R-squared value of fitted power law
  R2fitted_50 <- vector() #adjusted R-squared value of fitted power law
  R2fitted_50_c <- vector() #adjusted R-squared value of fitted power law
  R2fitted_10 <- vector() #adjusted R-squared value of fitted power law
  R2fitted_10_c <- vector() #adjusted R-squared value of fitted power law
  
  no_ASV <- vector() #ASV richness used with the coarse interval
  
  #For the coarse interval (every 5 %)
 
  for(sample_no in 1:length(com_binarized[1,])){
    #Number of ASVs harbored in each KO
    KO_dist <- t(KO_binarized) %*% com_binarized[, sample_no]
    s <- vector() #number of KOs with j time appearance
    for(j in 1:max(KO_dist)) {
      s[j] <- sum(KO_dist == j)
    } 
    #ASV richness and KO richness
    ASV_richness[sample_no] <- sum(com_binarized[, sample_no] > 0)
    KO_richness[sample_no] <- sum(KO_dist > 0)
    
    #Setting for the coarse interval
    interval <- ASV_richness[sample_no]/20   #every 5% changes in ASV richness
    no_ASV[1] <- 1
    for(k in 2:20) no_ASV[k] <- round(interval*(k - 1))
    no_ASV[21] <- ASV_richness[sample_no]

    #interpolation
    tau <- vector()
    for(x in 1:ASV_richness[sample_no]) tau[x] <- tau_chir(x, KO_richness[sample_no], ASV_richness[sample_no], s)
    
    #Setting for fitting power law 
    asv <- 1:ASV_richness[sample_no]
    
    #full range of ASV richness and the fine interval 
    fit_full <- lm(formula = log10(tau) ~ log10(asv))
    #full range and coarse interval
    fit_full_c <- lm(formula = log10(tau[no_ASV]) ~ log10(asv[no_ASV]))
    #0-50% reduction range and the fine interval
    fit_50 <- lm(formula = log10(tau[no_ASV[11]:ASV_richness[sample_no]]) ~ log10(asv[no_ASV[11]:ASV_richness[sample_no]]))
    #0-50% reduction range and the coarse interval
    fit_50_c <- lm(formula = log10(tau[no_ASV[11:21]]) ~ log10(no_ASV[11:21]))
    #0-90% reduction range and the fine interval
    fit_10 <- lm(formula = log10(tau[no_ASV[3]:ASV_richness[sample_no]]) ~ log10(asv[no_ASV[3]:ASV_richness[sample_no]]))
    #0-90% reduction range and the coarse interval
    fit_10_c <- lm(formula = log10(tau[no_ASV[3:21]]) ~ log10(no_ASV[3:21]))
    #Data summary
    tau_one[sample_no] <- tau[1]
    
    slope_full[sample_no] <- fit_full$coefficients[2]
    slope_full_down[sample_no] <- confint.lm(fit_full)[2, 1]
    slope_full_up[sample_no] <- confint.lm(fit_full)[2, 2]
    intercept_full[sample_no] <- 10^fit_full$coefficients[1]
    R2fitted_full[sample_no] <- summary(fit_full)$adj.r.squared
  
    slope_full_c[sample_no] <- fit_full_c$coefficients[2]
    slope_full_c_down[sample_no] <- confint.lm(fit_full_c)[2, 1]
    slope_full_c_up[sample_no] <- confint.lm(fit_full_c)[2, 2]
    intercept_full_c[sample_no] <- 10^fit_full_c$coefficients[1]
    R2fitted_full_c[sample_no] <- summary(fit_full_c)$adj.r.squared
    
    slope_50[sample_no] <- fit_50$coefficients[2]
    slope_50_down[sample_no] <- confint.lm(fit_50)[2, 1]
    slope_50_up[sample_no] <- confint.lm(fit_50)[2, 2]
    intercept_50[sample_no] <- 10^fit_50$coefficients[1]
    R2fitted_50[sample_no] <- summary(fit_50)$adj.r.squared
    
    slope_50_c[sample_no] <- fit_50_c$coefficients[2]
    slope_50_c_down[sample_no] <- confint.lm(fit_50_c)[2, 1]
    slope_50_c_up[sample_no] <- confint.lm(fit_50_c)[2, 2]
    intercept_50_c[sample_no] <- 10^fit_50_c$coefficients[1]
    R2fitted_50_c[sample_no] <- summary(fit_50_c)$adj.r.squared
    
    slope_10[sample_no] <- fit_10$coefficients[2]
    slope_10_down[sample_no] <- confint.lm(fit_10)[2, 1]
    slope_10_up[sample_no] <- confint.lm(fit_10)[2, 2]
    intercept_10[sample_no] <- 10^fit_10$coefficients[1]
    R2fitted_10[sample_no] <- summary(fit_10)$adj.r.squared
    
    slope_10_c[sample_no] <- fit_10_c$coefficients[2]
    slope_10_c_down[sample_no] <- confint.lm(fit_10_c)[2, 1]
    slope_10_c_up[sample_no] <- confint.lm(fit_10_c)[2, 2]
    intercept_10_c[sample_no] <- 10^fit_10_c$coefficients[1]
    R2fitted_10_c[sample_no] <- summary(fit_10_c)$adj.r.squared
    
    #log10-log10 scale fitting 
    plot(log10(asv), log10(tau), main = sample_info$Description[sample_ID[sample_no]], xlim = c(0, log10(ASV_richness[sample_no])), ylim = c(2.5, log10(max(tau))))
    abline(fit_full, col = 2, lwd = 2)
    abline(fit_10, col = 3, lwd = 2)
    abline(fit_50, col = 4, lwd = 2)
    abline(fit_full_c, col = 1, lty = "dashed")
    abline(fit_10_c, col = 1, lty = "dashed")
    abline(fit_50_c, col = 1, lty = "dashed")
    abline(v = log10(no_ASV[3]), col = 3, lty = "dashed", lwd = 2)
    abline(v = log10(no_ASV[11]), col = 4, lty = "dashed", lwd = 2)
    
    if(sample_no == 1) {
      pdf("figure02a.pdf", width = 10, height = 7, onefile = FALSE)
      plot(log10(asv), log10(tau), main = sample_info$Description[sample_ID[sample_no]], xlim = c(0, log10(ASV_richness[sample_no])), ylim = c(2.5, log10(max(tau))))
      abline(fit_full, col = 2, lwd = 2)
      abline(fit_10, col = 3, lwd = 2)
      abline(fit_50, col = 4, lwd = 2)
      abline(fit_full_c, col = 1, lty = "dashed")
      abline(fit_10_c, col = 1, lty = "dashed")
      abline(fit_50_c, col = 1, lty = "dashed")
      abline(v = log10(no_ASV[3]), col = 3, lty = "dashed", lwd = 2)
      abline(v = log10(no_ASV[11]), col = 4, lty = "dashed", lwd = 2)
      # Close the PostScript device
      dev.off()
    }
  }  
  #Summarizing results into dataframe
  summary_random_ext <- data.frame(
    sample = sample_info$Description[sample_ID], ASV_richness, KO_richness, 
    tau_one, 
    intercept_full, intercept_full_c, intercept_50, intercept_50_c, intercept_10, intercept_10_c,
    slope_full, slope_full_c, slope_50, slope_50_c, slope_10, slope_10_c,
    slope_full_down, slope_full_c_down, slope_50_down, slope_50_c_down, slope_10_down, slope_10_c_down,
    slope_full_up, slope_full_c_up, slope_50_up, slope_50_c_up, slope_10_up, slope_10_c_up,
    R2fitted_full, R2fitted_full_c, R2fitted_50, R2fitted_50_c, R2fitted_10, R2fitted_10_c
  )
  
  return(summary_random_ext)
}

Using the ASV table without converting by bacterial direct count

random_analytical <- random_extinction(stand_ASV_com_binarized, KO_com_binarized)

random_analytical

Variations between samples (Figure 2b)

#plot(random_analytical[, ])
asv_redundancy <- lm(slope_10_c ~ ASV_richness, data = random_analytical)
summary(asv_redundancy)

Call:
lm(formula = slope_10_c ~ ASV_richness, data = random_analytical)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.011978 -0.006656 -0.002459  0.006434  0.015596 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   1.551e-01  6.026e-03  25.742 3.51e-11 ***
ASV_richness -3.071e-05  3.200e-06  -9.596 1.12e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.008722 on 11 degrees of freedom
Multiple R-squared:  0.8933,    Adjusted R-squared:  0.8836 
F-statistic: 92.08 on 1 and 11 DF,  p-value: 1.115e-06
plot(
  slope_10_c ~ ASV_richness, data = random_analytical,
  pch = c(0,1,2,5,6)[as.factor(attributes_sample$location[sample_ID])],
  col = c(1,2,3,4,5,6)[as.factor(attributes_sample$date_sample[sample_ID])],
  xlab = "ASV richness", ylab = "multifunctional redundancy exponent (a)",
  ylim = c(0.06, 0.16)
)
abline(asv_redundancy)
legend("topright", legend = levels(as.factor(attributes_sample$location)), pch = c(0,1,2,5,6))
legend("bottomleft", legend = levels(as.factor(attributes_sample$date_sample[sample_ID])), col = c(1,2,3,4,5,6), pch = c(1,1,1,1,1,1))

#text(random_result$ASV_richness, random_result$slope,labels = attributes_sample$location[sample_ID], cex = 0.6, pos = 4, adj = 1)
pdf("figure02b.pdf", width = 10, height = 7, onefile = FALSE)

plot(
  slope_10_c ~ ASV_richness, data = random_analytical,
  pch = c(0,1,2,5,6)[as.factor(attributes_sample$location[sample_ID])],
  col = c(1,2,3,4,5,6)[as.factor(attributes_sample$date_sample[sample_ID])],
  xlab = "ASV richness", ylab = "multifunctional redundancy exponent (a)",
  ylim = c(0.06, 0.16)
)
abline(asv_redundancy)
legend("topright", legend = levels(as.factor(attributes_sample$location)), pch = c(0,1,2,5,6))
legend("bottomleft", legend = levels(as.factor(attributes_sample$date_sample[sample_ID])), col = c(1,2,3,4,5,6), pch = c(1,1,1,1,1,1))

# Close the PostScript device
dev.off()
null device 
          1 
[5.1.3’] When S11 is excluded
asv_redundancy2 <- lm(slope_10_c ~ ASV_richness, data = random_analytical[-9, ])
summary(asv_redundancy2)

Call:
lm(formula = slope_10_c ~ ASV_richness, data = random_analytical[-9, 
    ])

Residuals:
      Min        1Q    Median        3Q       Max 
-0.012297 -0.006936 -0.000970  0.006783  0.014510 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   1.566e-01  7.761e-03  20.183 1.96e-09 ***
ASV_richness -3.142e-05  3.964e-06  -7.927 1.28e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.009097 on 10 degrees of freedom
Multiple R-squared:  0.8627,    Adjusted R-squared:  0.849 
F-statistic: 62.83 on 1 and 10 DF,  p-value: 1.276e-05

[5.1.4] Note for the slope from random extinction

The slope was much shallower than those from Miki et al. 2014. This is probably because the unit of extinction is ASV but not the OTU or species. When the unit of extinction if ASV, the functional redundancy should be much greater than those between OTUs or species. In Miki et al. 2014, in most of simulations, we used the pseudo-communities where single species from a genus was included.

[5.2] Non-random extinction scenarios

Keywords: functional redundancy and functional vulnerability

[5.2.1] Loading the survival probability list

survival_rate <- readRDS("./Jan2024v3/survival_rate/survial_rate_del0ASV_exclu_undeter.eukar_AfterNeg_Jan2024.obj")
#adding random case
survival_rate_mod <- data.frame(random = rep(1, length(survival_rate[, 1])), 
                                F1 = survival_rate$KO_no_pa, 
                                F2 = survival_rate$KO_no_pa_inverse,
                                F3 = survival_rate$dist_KO_pa_mean,
                                F4 = survival_rate$dist_KO_pa_mean_inverse,
                                A1 = survival_rate$abundance_mean,
                                A2 = survival_rate$abundance_inverse_sd,
                                A3 = survival_rate$abundance_rich,
                                A4 = survival_rate$abundance_sha
                                )

[5.2.2] Trial of resampling with weighted probability

At each level of ASV richness, calculating the averages from repetition first and make a single line with averages

#for sample_1
presence <- which(stand_ASV_com_binarized$S01 > 0)
#ASV with greater richness of KOs (longer genomes) has a higher survival probability
prob_test <- prop.table(survival_rate_mod$F1[presence])
ASV_richness <- length(presence)
no_repetition <- 10
ASVs <- numeric(21)
KOs <- numeric(21)
KOs_temp <- numeric(no_repetition)
survived_ASVs <- list()
ASVs_full <- ASV_richness
KOs_full <- richness_MF$MF_G
survived_ASVs <- list()
s <- ASV_richness/20
slope <- numeric(no_repetition)

#Preparing survival sequences
for(j in 1:no_repetition) {
  #fully shuffling for the order of survival (the inverse order of extinction)
  survived_ASVs[[j]] <- sample(1:ASV_richness, size = ASV_richness, replace = FALSE, prob = prob_test)
  #survived_ASVs[[j]] <- sample(1:length(presence), size = length(presence), replace = FALSE)
}

#For plotting each survival sequence
for(j in 1:no_repetition) {
  #The case with a single ASV
  ASVs[1] <- 1
  KO_list_survived <- KO_com_binarized[survived_ASVs[[j]][1], ]
  KOs[1] <- sum(KO_list_survived > 0)
  for(k in 2:20) {
    survived_richness <- round(s*(k - 1))
    ASVs[k] <- survived_richness
    KO_survived <- KO_com_binarized[presence[survived_ASVs[[j]][1:survived_richness]], ]
    KO_list_survived <- apply(KO_survived, 2, sum)
    KOs[k] <- sum(KO_list_survived > 0)
  }
  #The case with all ASVs
  k <- 21
  ASVs[k] <- ASVs_full
  KOs[k] <- KOs_full
  
  fitted_power <- lm(formula = log10(KOs) ~ log10(ASVs))
  slope[j] <- fitted_power$coefficients[2]
  
  plot(log10(KOs) ~ log10(ASVs) , type = "l", xlim = c(log10(1), log10(ASVs[21])), ylim = c(log10(100), log10(KOs[21])), col = 8)
  par(new = T)
  #print(j)
}

#For plotting with averaging KOs at each survival level
#The case with a single ASV
ASVs[1] <- 1
for(j in 1:no_repetition) {
  KO_list_survived <- KO_com_binarized[survived_ASVs[[j]][1], ]
  KOs_temp[j] <- sum(KO_list_survived > 0)
}
KOs[1] <- mean(KOs_temp)
for(k in 2:20) {
  survived_richness <- round(s*(k - 1))
  ASVs[k] <- survived_richness
  for(j in 1:no_repetition) {
    KO_survived <- KO_com_binarized[presence[survived_ASVs[[j]][1:survived_richness]], ]
    KO_list_survived <- apply(KO_survived, 2, sum)
    KOs_temp[j] <- sum(KO_list_survived > 0)    
  }
  KOs[k] <- mean(KOs_temp)
}


k <- 21
ASVs[k] <- ASVs_full
KOs[k] <- KOs_full

fitted_power <- lm(formula = log10(KOs) ~ log10(ASVs))
slope <- fitted_power$coefficients[2]
  
plot(log10(KOs) ~ log10(ASVs) , type = "b", xlim = c(log10(1), log10(ASVs[21])), ylim = c(log10(100), log10(KOs[21])), cex = 2, col = 4, main = "Smaller KO richness goes extinct earlier")

#print(j)
confint.lm(fitted_power)
                2.5 %    97.5 %
(Intercept) 3.0439433 3.2292720
log10(ASVs) 0.2121199 0.2903613

[5.2.3] Simulations for a specific data set with all scenarios

At each level of ASV richness, calculating the averages from repetition first and make a single line with averages

#for sample_01
presence <- which(stand_ASV_com_binarized$S01 > 0)
#ASV with greater richness of KOs (longer genomes) has a higher survival probability

ASV_richness <- length(presence)
no_repetition <- 100
ASVs <- numeric(21)
KOs <- list()
KOs_temp <- numeric(no_repetition)
survived_ASVs <- list()
ASVs_full <- ASV_richness
KOs_full <- richness_MF$MF_G[1]
survived_ASVs <- list()
s <- ASV_richness/20
#Nine different scenarios, including the random-extinction scenario
for(i in 1:9) {
  KOs[[i]] <- numeric(21)
  
  prob_test <- prop.table(survival_rate_mod[, i][presence]) 
  
  #Preparing survival sequences
  for(j in 1:no_repetition) {
    #fully shuffling for the order of survival (the inverse order of extinction)
    survived_ASVs[[j]] <- sample(1:ASV_richness, size = ASV_richness, replace = FALSE, prob = prob_test)
    #survived_ASVs[[j]] <- sample(1:length(presence), size = length(presence), replace = FALSE)
  }
  
  #For plotting with averaging KOs at each survival level
  #The case with a single ASV
  ASVs[1] <- 1
  for(j in 1:no_repetition) {
    KO_list_survived <- KO_com_binarized[survived_ASVs[[j]][1], ]
    KOs_temp[j] <- sum(KO_list_survived > 0)
  }
  KOs[[i]][1] <- mean(KOs_temp)
  for(k in 2:20) {
    survived_richness <- round(s*(k - 1))
    ASVs[k] <- survived_richness
    for(j in 1:no_repetition) {
      KO_survived <- KO_com_binarized[presence[survived_ASVs[[j]][1:survived_richness]], ]
      KO_list_survived <- apply(KO_survived, 2, sum)
      KOs_temp[j] <- sum(KO_list_survived > 0)    
    }
    KOs[[i]][k] <- mean(KOs_temp)
  }
  
  k <- 21
  ASVs[k] <- ASVs_full
  KOs[[i]][k] <- KOs_full
  
  color_specific <- c("black", "darkgoldenrod1","coral1","hotpink3", "brown4", "lightslategray", "deepskyblue", "royalblue4", "seagreen3")
  
  
  if(i == 1) {
    plot(KOs[[i]][2:21] ~ ASVs[2:21] , type = "b", xlim = c(ASVs[2], ASVs[21]), ylim = c(3000, KOs[[i]][21]), cex = 2, col = color_specific[i], main = "All scenarios for Biwa0703", xlab = "ASV richness", ylab = "KO richness")  
  } else {
    par(new = T)
    plot(KOs[[i]][2:21] ~ ASVs[2:21] , type = "b", xlim = c(ASVs[2], ASVs[21]), ylim = c(3000, KOs[[i]][21]), cex = 2, col = color_specific[i], pch = i, main = "", xlab = "", ylab = "")
  }
  labels <- colnames(survival_rate_mod)
legend("bottomright", legend = labels, col = color_specific, pch = 1:9)
  
}


for(i in 1:9){
  if(i == 1) {
    plot(log10(KOs[[i]][2:21]) ~ log10(ASVs[2:21]), type = "b", xlim = c(log10(ASVs[2]), log10(ASVs[21])), ylim = c(log10(3000), log10(KOs[[i]][21])), cex = 2, col = color_specific[i], main = "All scenarios for Biwa0703", xlab = "ASV richness", ylab = "KO richness")  
  } else {
    par(new = T)
    plot(log10(KOs[[i]][2:21]) ~ log10(ASVs[2:21]), type = "b", xlim = c(log10(ASVs[2]), log10(ASVs[21])), ylim = c(log10(3000), log10(KOs[[i]][21])), cex = 2, col = color_specific[i], pch = i, main = "", xlab = "", ylab = "")
  }
  labels <- colnames(survival_rate_mod)
  legend("bottomright", legend = labels, col = color_specific, pch = 1:9)
}

pdf("figure03a.pdf", width = 10, height = 7, onefile = FALSE)
for(i in 1:9){
  if(i == 1) {
    plot(KOs[[i]][2:21] ~ ASVs[2:21] , type = "b", xlim = c(ASVs[2], ASVs[21]), ylim = c(3000, KOs[[i]][21]), cex = 2, col = color_specific[i], main = "All scenarios for Biwa0703", xlab = "ASV richness", ylab = "KO richness")  
  } else {
    par(new = T)
    plot(KOs[[i]][2:21] ~ ASVs[2:21] , type = "b", xlim = c(ASVs[2], ASVs[21]), ylim = c(3000, KOs[[i]][21]), cex = 2, col = color_specific[i], pch = i, main = "", xlab = "", ylab = "")
  }
}
labels <- colnames(survival_rate_mod)
legend("bottomright", legend = labels, col = color_specific, pch = 1:9)
dev.off()
png 
  2 

At each level of ASV richness, calculating the averages from repetition first and make a single line with averages

#for sample_05
presence <- which(stand_ASV_com_binarized$S05 > 0)
#ASV with greater richness of KOs (longer genomes) has a higher survival probability

ASV_richness <- length(presence)
no_repetition <- 100
ASVs <- numeric(21)
KOs <- list()
KOs_temp <- numeric(no_repetition)
survived_ASVs <- list()
ASVs_full <- ASV_richness
KOs_full <- richness_MF$MF_G[5]
survived_ASVs <- list()
s <- ASV_richness/20
#Nine different scenarios, including the random-extinction scenario
for(i in 1:9) {
  KOs[[i]] <- numeric(21)
  
  prob_test <- prop.table(survival_rate_mod[, i][presence]) 
  
  #Preparing survival sequences
  for(j in 1:no_repetition) {
    #fully shuffling for the order of survival (the inverse order of extinction)
    survived_ASVs[[j]] <- sample(1:ASV_richness, size = ASV_richness, replace = FALSE, prob = prob_test)
    #survived_ASVs[[j]] <- sample(1:length(presence), size = length(presence), replace = FALSE)
  }
  
  #For plotting with averaging KOs at each survival level
  #The case with a single ASV
  ASVs[1] <- 1
  for(j in 1:no_repetition) {
    KO_list_survived <- KO_com_binarized[survived_ASVs[[j]][1], ]
    KOs_temp[j] <- sum(KO_list_survived > 0)
  }
  KOs[[i]][1] <- mean(KOs_temp)
  for(k in 2:20) {
    survived_richness <- round(s*(k - 1))
    ASVs[k] <- survived_richness
    for(j in 1:no_repetition) {
      KO_survived <- KO_com_binarized[presence[survived_ASVs[[j]][1:survived_richness]], ]
      KO_list_survived <- apply(KO_survived, 2, sum)
      KOs_temp[j] <- sum(KO_list_survived > 0)    
    }
    KOs[[i]][k] <- mean(KOs_temp)
  }
  
  k <- 21
  ASVs[k] <- ASVs_full
  KOs[[i]][k] <- KOs_full
  
  if(i == 1) {
    plot(KOs[[i]][2:21] ~ ASVs[2:21] , type = "b", xlim = c(ASVs[2], ASVs[21]), ylim = c(3000, KOs[[i]][21]), cex = 2, col = color_specific[i], main = "All scenarios for Yasu0709", xlab = "ASV richness", ylab = "KO richness")  
  } else {
    par(new = T)
    plot(KOs[[i]][2:21] ~ ASVs[2:21] , type = "b", xlim = c(ASVs[2], ASVs[21]), ylim = c(3000, KOs[[i]][21]), cex = 2, col = color_specific[i], pch = i, main = "", xlab = "", ylab = "")
  }
  labels <- colnames(survival_rate_mod)
legend("bottomright", legend = labels, col = color_specific, pch = 1:9)
  
}


for(i in 1:9){
  if(i == 1) {
    plot(log10(KOs[[i]][2:21]) ~ log10(ASVs[2:21]), type = "b", xlim = c(log10(ASVs[2]), log10(ASVs[21])), ylim = c(log10(3000), log10(KOs[[i]][21])), cex = 2, col = color_specific[i], main = "All scenarios for Yasu0709", xlab = "ASV richness", ylab = "KO richness")  
  } else {
    par(new = T)
    plot(log10(KOs[[i]][2:21]) ~ log10(ASVs[2:21]), type = "b", xlim = c(log10(ASVs[2]), log10(ASVs[21])), ylim = c(log10(3000), log10(KOs[[i]][21])), cex = 2, col = color_specific[i], pch = i, main = "", xlab = "", ylab = "")
  }
  labels <- colnames(survival_rate_mod)
  legend("bottomright", legend = labels, col = color_specific, pch = 1:9)
}

pdf("figure03b.pdf", width = 10, height = 7, onefile = FALSE)
for(i in 1:9){
  if(i == 1) {
    plot(KOs[[i]][2:21] ~ ASVs[2:21] , type = "b", xlim = c(ASVs[2], ASVs[21]), ylim = c(3000, KOs[[i]][21]), cex = 2, col = color_specific[i], main = "All scenarios for Yasu0709", xlab = "ASV richness", ylab = "KO richness")  
  } else {
    par(new = T)
    plot(KOs[[i]][2:21] ~ ASVs[2:21] , type = "b", xlim = c(ASVs[2], ASVs[21]), ylim = c(3000, KOs[[i]][21]), cex = 2, col = color_specific[i], pch = i, main = "", xlab = "", ylab = "")
  }
}
labels <- colnames(survival_rate_mod)
legend("bottomright", legend = labels, col = color_specific, pch = 1:9)
dev.off()
png 
  2 

[5.2.4] Definition of functions for a given extinction sequence

sample_ID <- c(1, 2, 3, 4, 5, 6, 7, 8, 11, 17, 18, 19, 20) #only a part of samples is used
###list of parameters###
#com_binarized: ASV composition dataframe binarized
#KO_binarized: KO composition dataframe binarized
#surv_prob: extinction sequences (with replications) as a list
sim_extinction <- function(com_binarized, KO_binarized, surv_prob = NULL, repetition, title = "random", graphic = TRUE) {
  presence <- numeric(length(sample_ID))
  ASVs_full <- numeric(length(sample_ID))
  KOs_full <- numeric(length(sample_ID))
  slope <- numeric(length(sample_ID))
  slope_up <- numeric(length(sample_ID))
  slope_down <- numeric(length(sample_ID))
  r2_adjusted <- numeric(length(sample_ID))
  
  #for(sample_no in 1:2){
  for(sample_no in 1:length(com_binarized[1,])){
    presence <- which(com_binarized[, sample_no] > 0)
    ASV_richness <- length(presence)
    ASVs <- numeric(21)
    KOs <- numeric(21)
    KOs_temp <- numeric(repetition)
    survived_ASVs <- list()
    ASVs_full[sample_no] <- ASV_richness
    KOs_full[sample_no] <- sum(t(KO_binarized) %*% com_binarized[, sample_no] > 0)
    s <- ASV_richness/20
    
    #Refresh the graphics for each sample_no
    par(new = F)
    
    #Setting survival probability
    if(is.null(surv_prob)) {
      survival_prob <- NULL
    } else {
      survival_prob <- surv_prob[presence]
    }
    
    #Preparing survival sequences
    for(j in 1:repetition) {
      #fully shuffling for the order of appearance (the inverse order of extinction)
      survived_ASVs[[j]] <- sample(1:length(presence), size = length(presence), replace = FALSE, prob = survival_prob)
    }
    #For plotting each extinction sequence
    for(j in 1:repetition) {
      #The case with a single ASV
      #ASVs[1] <- 1
      #KO_list_survived <- KO_binarized[survived_ASVs[[j]][1], ]
      #KOs[1] <- sum(KO_list_survived > 0)
      for(k in 3:20) {
        survived_richness <- round(s*(k - 1))
        ASVs[k] <- survived_richness
        KO_survived <- KO_binarized[presence[survived_ASVs[[j]][1:survived_richness]], ]
        KO_list_survived <- apply(KO_survived, 2, sum)
        KOs[k] <- sum(KO_list_survived > 0)
      }
      #The case with all ASVs
      k <- 21
      ASVs[k] <- ASVs_full[sample_no]
      KOs[k] <- KOs_full[sample_no]
  
      #fitted_power <- lm(formula = log10(KOs) ~ log10(ASVs))
      #slope_each[j] <- fitted_power$coefficients[2]
      if(graphic == TRUE) {
        plot(log10(KOs[3:21]) ~ log10(ASVs[3:21]) , type = "l", xlim = c(log10(ASVs[3]), log10(ASVs[21])), ylim = c(log10(3000), log10(KOs[21])), col = 8)
        par(new = T)
      }
      #print(j)
    }#end of for j
    
    #For plotting with averaging KOs at each survival level
    #The case with a single ASV
    #ASVs[1] <- 1
    for(j in 1:repetition) {
      KO_list_survived <- KO_binarized[survived_ASVs[[j]][1], ]
      KOs_temp[j] <- sum(KO_list_survived > 0)
    }
    KOs[1] <- mean(KOs_temp)
    for(k in 3:20) {
      survived_richness <- round(s*(k - 1))
      ASVs[k] <- survived_richness
      for(j in 1:repetition) {
        KO_survived <- KO_binarized[presence[survived_ASVs[[j]][1:survived_richness]], ]
        KO_list_survived <- apply(KO_survived, 2, sum)
        KOs_temp[j] <- sum(KO_list_survived > 0)    
      }
      KOs[k] <- mean(KOs_temp)
    }

    k <- 21
    ASVs[k] <- ASVs_full[[sample_no]]
    KOs[k] <- KOs_full[[sample_no]]
    #0-90% reduction with the coarse interval
    fitted_power <- lm(formula = log10(KOs[3:21]) ~ log10(ASVs[3:21]))
    slope[sample_no] <- fitted_power$coefficients[2]
    
    title_text <- paste(sample_info$Description[sample_ID[sample_no]], title, sep = ":")
    if(graphic == TRUE) {
      plot(log10(KOs[3:21]) ~ log10(ASVs[3:21]) , type = "b", xlim = c(log10(ASVs[3]), log10(ASVs[21])), ylim = c(log10(3000), log10(KOs[21])), cex = 2, col = 4, main = title_text)
#print(j)
      abline(fitted_power, col = 5)
    }
    slope_down[sample_no] <- confint.lm(fitted_power)[2, 1]
    slope_up[sample_no] <- confint.lm(fitted_power)[2, 2]
    r2_adjusted[sample_no] <- summary(fitted_power)$adj.r.squared

  }#end of for sample_no
  summary_extinction <- data.frame(sample = sample_info$Description[sample_ID], ASVs_full, KOs_full, slope, slope_down, slope_up, r2_adjusted)
  
  return(summary_extinction)
}

[5.2.5] Parallel calculation for non-randon extinctions w/o graphics

#set.seed(1234567)
nonrandom_sim <- list()

labels <- colnames(survival_rate_mod)

nonrandom_sim <- mclapply(1:9, function(i) {
  result_sim <- sim_extinction(stand_ASV_com_binarized, KO_com_binarized, surv_prob = survival_rate_mod[, i], repetition = 100, title = labels[i], graphic = FALSE)
  result_sim
}, mc.cores = 9)

Results

nonrandom_sim
[[1]]

[[2]]

[[3]]

[[4]]

[[5]]

[[6]]

[[7]]

[[8]]

[[9]]
NA

[5.2.6] Summary

Preparing a dataframe for graphic presentation

slope_r <- list()
for(j in 1:9) {
  slope_r[[j]] <- nonrandom_sim[[j]]$slope
}
slope_summary <- NULL
for(j in 1:9) {
  slope_summary <- append(slope_summary, slope_r[[j]])
}
length(slope_summary)
[1] 117
sample_id <- rep(nonrandom_sim[[1]]$sample, 9)
sites <- rep(c("biwa", "ane", "echi", "hino", "yasu", "biwa", "ane", "echi", "biwa", "ane", "echi", "hino", "yasu"), 9)
dates <- rep(c("20190703", "20190709", "20190709", "20190709", "20190709", "20190730", "20190807", "20190807", "20190910", "20191015", "20191015", "20191015", "20191015"), 9)
xtype <- c(rep("random", 13), rep("F1", 13), rep("F2", 13), rep("F3", 13), rep("F4", 13), rep("A1", 13), rep("A2", 13), rep("A3", 13), rep("A4", 13))
xtype_n <- c(rep(1, 13), rep(2, 13), rep(3, 13), rep(4, 13), rep(5, 13), rep(6, 13), rep(7, 13), rep(8, 13), rep(9, 13))
slope_2 <- slope_summary - rep(slope_summary[1:13], 9) #normalized by random scenario through substraction
slope_3 <- slope_summary/rep(slope_summary[1:13], 9) #normalized by random scenario through division
  
slope_summary2 <- data.frame(dates, sites, xtype, xtype_n, slope = slope_summary, slope_ns = slope_2, slope_nd <- slope_3)
slope_summary2$xtype2 <- factor(slope_summary2$xtype, levels=c("random", "F1", "F2", "F3", "F4", "A1", "A2", "A3", "A4"))

Figure 4

custom_labels <- c("random", "F1", "F2", "F3", "F4", "A1", "A2", "A3", "A4")
fig4_no1 <- ggplot(data = slope_summary2) +
 geom_line(aes(x = xtype_n, y = slope, group = sample_id, color = dates)) +
  geom_point(aes(x = xtype_n, y = slope, color = dates, shape = sites), size = 3) +
  scale_x_continuous(breaks = c(1:9), labels = custom_labels) + scale_shape_manual(values = c(15, 16, 17, 5, 6)) + theme_bw() +   
  labs (title = "Direct comparison of exponents", x = "extinction scenarios", y = "redundancy exponent (a)") 

fig4_no2 <- ggplot(data = slope_summary2) +
 geom_line(aes(x = xtype_n, y = slope_ns, group = sample_id, color = dates)) +
  geom_point(aes(x = xtype_n, y = slope_ns, color = dates, shape = sites), size = 3) +
  scale_x_continuous(breaks = c(1:9), labels = custom_labels) + scale_shape_manual(values = c(15, 16, 17, 5, 6)) + theme_bw() +    
  labs (title = "Comparison through substracting random scenario of exponents", x = "extinction scenarios", y = "redundancy exponent (a)") 

fig4_no3 <- ggplot(data = slope_summary2) +
 geom_line(aes(x = xtype_n, y = slope_nd, group = sample_id, color = dates)) +
  geom_point(aes(x = xtype_n, y = slope_nd, color = dates, shape = sites), size = 3) +
  scale_x_continuous(breaks = c(1:9), labels = custom_labels) + scale_shape_manual(values = c(15, 16, 17, 5, 6)) + theme_bw() +   
 labs (title = "Comparison through divising by random scenario of exponents", x = "extinction scenarios", y = "redundancy exponent (a)") 

fig4_no4 <- ggplot(slope_summary2, aes(xtype2, slope_ns))+
    geom_boxplot(outlier.shape = NA)+
    geom_jitter(aes(shape = sites, color = dates),width = 0.25, size = 3)+
    scale_shape_manual(values = c(15, 16, 17, 5, 6))+
    theme_bw() +
    labs (title = "Comparison through substracting random scenario of exponents", x = "Extinction scenarios", y = "Redundancy exponent (a)") 

plot(fig4_no1)

plot(fig4_no2)

plot(fig4_no3)

plot(fig4_no4)

pdf("figure04a.pdf", width = 10, height = 7, onefile = FALSE)
plot(fig4_no1)
# Close the PostScript device
dev.off()
png 
  2 
pdf("figure04b.pdf", width = 10, height = 7, onefile = FALSE)
plot(fig4_no4)
# Close the PostScript device
dev.off()
png 
  2 

[6] Assembly from the metacommunity

[6.1] Definition of function for a given scenario with the metacommunity

At each level of ASV richness for each extinction scenario, preparing 200 replications

sim_extinctionM <- function(com_binarized, KO_binarized, surv_prob = NULL, no_repetition, scenario = "S1") {
  ASV_richnessM <- length(com_binarized[, 1])
  KO_richnessM <- sum(apply(KO_binarized, 2, sum) > 0)
  prob_testM <- prop.table(surv_prob)
  ASVsM <- numeric(21)
  KOs_tempM <- numeric(no_repetition)
  KOs_975 <- numeric(21)
  KOs_025 <- numeric(21)
  KOs_mean <- numeric(21)
  survived_ASVsM <- list()
  s <- ASV_richnessM/20  
  
  #Preparing survival sequences
  for(j in 1:no_repetition) {
    #fully shuffling for the order of survival (the inverse order of extinction)
    survived_ASVsM[[j]] <- sample(1:ASV_richnessM, size = ASV_richnessM, replace = FALSE, prob = prob_testM)
  }
  
  k <- 1
  ASVsM[k] <- 100
  for(j in 1:no_repetition) {
    KO_survived <- KO_com_binarized[survived_ASVsM[[j]][1:ASVsM[k]], ]
    KO_list_survived <- apply(KO_survived, 2, sum)
    KOs_tempM[j] <- sum(KO_list_survived > 0)
  }
  KOs_mean[k] <- mean(KOs_tempM)  #mean of the replications
  KOs_975[k] <- quantile(KOs_tempM, prob = 0.975) #Upper boundary of 95% confidence interval
  KOs_025[k] <- quantile(KOs_tempM, prob = 0.025) #Lower boundary of 95% confidence interval

  for(k in 2:20) {
    ASVsM[k] <- round(s*(k - 1))
    for(j in 1:no_repetition) {
      KO_survived <- KO_com_binarized[survived_ASVsM[[j]][1:ASVsM[k]], ]
      KO_list_survived <- apply(KO_survived, 2, sum)
      KOs_tempM[j] <- sum(KO_list_survived > 0)
    }
    KOs_mean[k] <- mean(KOs_tempM)  #mean of the replications
    KOs_975[k] <- quantile(KOs_tempM, prob = 0.975) #Upper boundary of 95% confidence interval
    KOs_025[k] <- quantile(KOs_tempM, prob = 0.025) #Lower boundary of 95% confidence interval
  }
  #The case with all ASVs
  k <- 21
  ASVsM[k] <- ASV_richnessM
  KOs_mean[k] <- KO_richnessM
  KOs_975[k] <- KO_richnessM
  KOs_025[k] <- KO_richnessM
  
  simM <- data.frame(s = rep(scenario, 21), ASV_richness = ASVsM, KOs_mean, KOs_975, KOs_025)
  return(simM)  
}

[6.2] Trial

test_randomM <- sim_extinctionM(stand_ASV_com_binarized, KO_com_binarized, surv_prob = survival_rate_mod$F1, no_repetition = 10, scenario = "random")

#For KO richness plot
meta_plot <- ggplot(data = test_randomM) + geom_line(aes(x = ASV_richness, y = KOs_mean))
meta_plot <- meta_plot + geom_ribbon(aes(x = ASV_richness, ymin = KOs_025, ymax = KOs_975), fill = "red", alpha = 0.5)
plot(meta_plot)

meta_plot <- meta_plot + geom_point(data = richness_MF, aes(x = ASV_richness, y = MF_G, shape = richness_MF$location), size = 3, alpha = 0.9) + labs(shape = "sites") + scale_shape_manual(values = c(0, 1, 2, 5, 6)) 
plot(meta_plot)

[6.3] Parallel calculations for metacommunity extinctions

meta_sim <- mclapply(1:9, function(i) {
  
  result_sim <- sim_extinctionM(stand_ASV_com_binarized, KO_com_binarized, surv_prob = survival_rate_mod[, i], no_repetition = 200, scenario = colnames(survival_rate_mod)[i])
  
  result_sim
}, mc.cores = 9)
meta_sim
[[1]]

[[2]]

[[3]]

[[4]]

[[5]]

[[6]]

[[7]]

[[8]]

[[9]]
NA

[6.4] Visualization

[6.4.1] Comparision of realized communities with a single scenario from the metacommunity

meta_plot_j <- list()
for(j in 1:9) {
  meta_plot <- ggplot(data = meta_sim[[j]]) + geom_line(aes(x = ASV_richness, y = KOs_mean))
  meta_plot <- meta_plot + geom_ribbon(aes(x = ASV_richness, ymin = KOs_025, ymax = KOs_975), fill = j, alpha = 0.5)
  #random range
  meta_plot <- meta_plot + geom_line(data = meta_sim[[1]], aes(x = ASV_richness, y = KOs_025), linetype = "dashed") 
  meta_plot <- meta_plot + geom_line(data = meta_sim[[1]], aes(x = ASV_richness, y = KOs_975), linetype = "dashed") 

  meta_plot <- meta_plot + geom_point(data = richness_MF, aes(x = ASV_richness, y = MF_G, shape = richness_MF$location), size = 3, alpha = 0.9) + labs(shape = "sites") + scale_shape_manual(values = c(0, 1, 2, 5, 6))   
  meta_plot_j[[j]] <- meta_plot
}

for(j in 1:9){
  plot(meta_plot_j[[j]])
}

For generating pdfs

for(j in 2:5){
  file_name <- paste("figure05_", j-1, ".pdf", sep = "")
  pdf(file_name, width = 10, height = 7, onefile = FALSE)
  plot(meta_plot_j[[j]])
  # Close the PostScript device
  dev.off()
}

for(j in 6:9){
  file_name <- paste("figureS2_", j-5, ".pdf", sep = "")
  pdf(file_name, width = 10, height = 7, onefile = FALSE)
  plot(meta_plot_j[[j]])
  # Close the PostScript device
  dev.off()
}

[6.4.2] All scenarios together

meta_sim_all <- NULL
for(j in 1:9) {
  meta_sim_all <- rbind.data.frame(meta_sim_all, meta_sim[[j]])
}

#ribbon plot
meta_plot_all <- ggplot(data = meta_sim_all) #+ geom_line(aes(x = ASV_richness, y = KOs_mean, group = s, color = s))
for(j in 1:5) {
  start <- 1 + 21*(j - 1)
  end <- 21*j
  meta_plot_all <- meta_plot_all + geom_ribbon(data = meta_sim_all[start:end, ], aes(x = ASV_richness, ymin = KOs_025, ymax = KOs_975), fill = j, alpha = 0.5)
}
meta_plot_all <- meta_plot_all + geom_point(data = richness_MF, aes(x = ASV_richness, y = MF_G, shape = richness_MF$location), size = 3, alpha = 0.4) + labs(shape = "sites") + scale_shape_manual(values = c(0, 1, 2, 5, 6)) 
plot(meta_plot_all)


#line plot
meta_plot_all <- ggplot(data = meta_sim_all) #+ geom_line(aes(x = ASV_richness, y = KOs_mean, group = s, color = s))
for(j in 1:5) {
  start <- 1 + 21*(j - 1)
  end <- 21*j
  meta_plot_all <- meta_plot_all + geom_line(data = meta_sim_all[start:end, ], aes(x = ASV_richness, y = KOs_025), color = j)
  meta_plot_all <- meta_plot_all + geom_line(data = meta_sim_all[start:end, ], aes(x = ASV_richness, y = KOs_975), color = j)
}
meta_plot_all <- meta_plot_all + geom_point(data = richness_MF, aes(x = ASV_richness, y = MF_G, shape = richness_MF$location), size = 3, alpha = 0.4) + labs(shape = "sites") + scale_shape_manual(values = c(0, 1, 2, 5, 6)) 
plot(meta_plot_all)

[7] For Supporting Information

[7.0] Correlation between bacterial abundance and ASV richness

plot(
  data_summary$stand_ASV_richness[sample_ID] ~ data_summary$bacterial.abundance[sample_ID],
  pch = c(0,1,2,5,6)[as.factor(data_summary$location[sample_ID])],
  col = c(1,2,3,4,5,6)[as.factor(attributes_sample$date_sample[sample_ID])],
  xlab = "Bacterial Abundance (cells/mL)", ylab = "ASV richness"
)
legend("topright", legend = levels(as.factor(data_summary$location)), pch = c(0,1,2,5,6))

#legend("bottomleft", legend = levels(as.factor(data_summary$date_sample[sample_ID])), col = c(1,2,3,4,5,6), pch = c(1,1,1,1,1,1))

[7.1] Correlation between KO-based functional traits

Cite: Why are some microbes more ubiquitous than others? Predicting the habitat breadth of soil bacteria, Ecology Letters, (2014) 17: 794–802 doi: 10.1111/ele.12282

plot(survival_rate_mod$F4 ~ survival_rate_mod$F2, 
     xlab = "Inverse of KO richness",
     ylab = "Inverse of the mean dissimilarity"
     )


plot(log10(survival_rate_mod$A1) ~ survival_rate_mod$F1,
     xlab = "KO richness",
     ylab = "log10(mean abundance)"
     )
f1_a1_model <- lm(log10(A1) ~ F1, data = survival_rate_mod)
summary(f1_a1_model)

Call:
lm(formula = log10(A1) ~ F1, data = survival_rate_mod)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.57323 -0.38115  0.02451  0.41292  2.93730 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 2.171e+00  4.105e-02    52.9   <2e-16 ***
F1          4.611e-04  3.468e-05    13.3   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6916 on 3574 degrees of freedom
Multiple R-squared:  0.04715,   Adjusted R-squared:  0.04688 
F-statistic: 176.9 on 1 and 3574 DF,  p-value: < 2.2e-16
abline(f1_a1_model)


plot(survival_rate_mod$A3 ~ survival_rate_mod$F1, 
     xlab = "KO richness",
     ylab = "No. of occurrence")

f1_a3_model <- lm(A3 ~ F1, data = survival_rate_mod)
summary(f1_a3_model)

Call:
lm(formula = A3 ~ F1, data = survival_rate_mod)

Residuals:
    Min      1Q  Median      3Q     Max 
-8.6984 -2.0013 -0.0598  1.9386  7.5665 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 3.9165322  0.1580728   24.78   <2e-16 ***
F1          0.0020724  0.0001335   15.52   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.663 on 3574 degrees of freedom
Multiple R-squared:  0.06313,   Adjusted R-squared:  0.06286 
F-statistic: 240.8 on 1 and 3574 DF,  p-value: < 2.2e-16
abline(f1_a3_model)

plot(survival_rate_mod[, -1])

[7.2] Another method to calculate functionally uniqueness

Based on the # of KOs that are not shared with all other ASVs

[7.3] Direct fitting of power-law regression to the all data

This could be directly compared to Fig.3 in Ruhl et al. 2022

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayBmb3Igc3VtaXRvbW8gYmFjdGVyaWFsIGZ1bmN0aW9uYWwgcmVkdW5kYW5jeSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpXaXRoIFdhbi1oc3Vhbiwgc3RhcnRpbmcgZnJvbSAyMDIzIE9jdAoKIyMgWzFdIEV4cGVyaW1lbnRhbCBwcm90b2NvbHMKIyMjIFsxLjFdIFNhbXBsaW5nIGxvY2F0aW9ucyBhbmQgZGF0ZXMKIyMjIyBbMS4xLjFdIExvY2F0aW9ucwoxKSBTdG4uSWUtMSBpbiB0aGUgbm9ydGggYmFzaW4gb2YgTGFrZSBCaXdhOiBJZS0xIDM1wrAxMic1OCJOIDEzNcKwNTknNTUiRQoyKSBZYXN1IHJpdmVyOiAzNcKwMDInMzUuNSJOIDEzNsKwMDEnMTAuMCJFCjMpIEhpbm8gcml2ZXI6IDM1wrAwNicwOS4xIk4gMTM2wrAwNCczNy40IkUKNCkgRWNoaSByaXZlcjogMzXCsDExJzQ0LjAiTiAxMzbCsDEwJzQ2LjUiRQo1KSBBbmUgcml2ZXI6IDM1wrAyNCc0NS4xIk4gMTM2wrAxNic1OS4wIkUKCiMjIyMjIFsxLjEuMl0gRGF0ZXMKMSkgTGFrZSBCaXdhOiAyMDE5LzA3LzAzLCAwNy8zMCwgMDkvMTAsIDEwLzE3CjIpIEZvdXIgcml2ZXJzOiAyMDE5LzA3LzA5LCAwOC8wNywgMDkvMTcsIDEwLzE1CgojIyMgWzEuMl0gU2FtcGxpbmcgbWV0aG9kcwojIyMjIFsxLjIuMV0gQ29sbGVjdGlvbiBvZiBwcm9rYXJ5b3RpYyBETkE6IEZpbHRlcmluZyBXYXRlcgotIFNURVJJVkVYLUdWIDAuMjJVTSBQVkRGCgojIyMgWzEuM10gMXN0IGFuZCAybmQgUENSCiMjIyMgWzEuMy4xXSBQcmltZXJzCkM6XFVzZXJzXGJpb21pa2lcRHJvcGJveFxhY3RpdmVfUlxleHBlcmltZW50X2Zyb20yMDE5XHN1bWl0b21vXGV4cGVyaW1lbnRzXDFzdF8ybmRfUENSXGRuYV92MTA2X2h0c190dWJlX2pwX29yZGVyZm9ybTIwMTkxMjA0LnhscwpFdXJvZmlucyAoNTE1RiwgODA2UikKIyMjIFsxLjVdIE1pc2VxIHNlcXVlbmNlIChSdW4gSUQ6IFJNUjE1MikKCiMjIFsyXSBCaW9pbmZvcm1hdGljcy9tb2RlbGluZyBwcm90b2NvbHMKIyMjIFsyLjBdIEdlbmVyYXRpbmcgRmFzdHEgZmlsZXMgd2l0aG91dCBkZW11bHRpcGxleGluZyAoYmNsMmZhc3RxIHYyLjE4KQojIyMgWzIuMV0gVGFnIGFuZCBQcmltZXIgRmlsdGVyaW5nIGFuZCBEZW11bHRpcGxleCBieSBjbGFpZGVudCAodmVyc2lvbiB2MC4yLjIwMTguMDUuMjkpCiMjIyBbMi4yXSBkYWRhMiBmb3IgQVNWIGNvbXBvc2l0aW9uCiMjIyBbMi4zXSBQaUNSVVN0MiBmb3IgS08gY29tcG9zaXRpb24gZm9yIGVhY2ggQVNWCgojIyBbM10gTG9hZGluZyBhbmQgc3VtbWFyaXppbmcgZGF0YQojIyMgWzMuMF0gTG9hZGluZyBwYWNrYWdlcyAmIHNldHRpbmcgcmFuZG9tIHNlZWQKYGBge3J9CmxpYnJhcnkodmVnYW4pCmxpYnJhcnkoZ2dlZmZlY3RzKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGFyYWxsZWwpCnNldC5zZWVkKDEyMzQ1NjcpCmBgYAoKIyMjIFszLjFdIExvYWRpbmcgZGF0YSAKIyMjIyBbMy4xLjFdIExvYWRpbmcgc2FtcGxlIGluZm9ybWF0aW9uIGZvciBNaXNlcQpgYGB7cn0Kc2FtcGxlX2luZm8gPC0gcmVhZC5jc3YoIlNhbXBsZVNoZWV0X1JNUjE1Mi5jc3YiLCBza2lwID0gMTksIGhlYWRlciA9IFQpCnNhbXBsZV9pbmZvCmBgYAoKIyMjIyBbMy4xLjJdIEJhY3RlcmlhbCBkaXJlY3QgY291bnQKYGBge3J9CiNsb2FkaW5nIGRhdGEKcmF3X2JhY19jb3VudCA8LSByZWFkLmNzdigiYmFjdGVyaWFsX2NvdW50X3N1bWl0b21vLmNzdiIsIGhlYWRlciA9IFQpCnJhd19iYWNfY291bnQKI2NhbGN1bGF0aW5nIHRoZSBhdmVyYWdlcyBvZiB0ZW4gcmVwZXRpdGlvbnMgZm9yIGVhY2ggZXhhbXBsZQphdmVyYWdlIDwtIGFwcGx5KHJhd19iYWNfY291bnRbMzoxMl0sIDEsIG1lYW4pCiNjb252ZXJ0aW5nIHRoZSBhdmVyYWdlZCByYXcgY291bnQgdG8gY2VsbCBkZW5zaXR5IChjZWxscy9tTCkgdXNpbmcgY29udmVyc2lvbiBmYWN0b3JzCkEgPC0gMjEwICNlZmZlY3RpdmUgZmlsdGVyZWQgYXJlYSAobW1eMikKRyA8LSA3Nyo3NyoxLjBlLTYgI2FyZWEgb2Ygb25lIHZpc2lvbiAobW1eMikKViA8LSAxLjAgICN2b2x1bWUgb2YgZmlsdGVyZWQgc2FtcGxlIChtbCkKY2VsbF9kZW5zaXR5IDwtIGF2ZXJhZ2UqKEEvRykvVgojaW50ZWdyYXRpbmcgaW50byB0aGUgZGF0YWZyYW1lCmJhY19jZWxsX2RlbnNpdHkgPC0gZGF0YS5mcmFtZShtb250aCA9IHJhd19iYWNfY291bnQkbW9udGgsIGxvY2F0aW9uID0gcmF3X2JhY19jb3VudCRyaXZlciwgYXZlcmFnZV9jb3VudCA9IGF2ZXJhZ2UsIGRlbnNpdHkgPSBjZWxsX2RlbnNpdHkpCmJhY19jZWxsX2RlbnNpdHkKc2F2ZVJEUyhiYWNfY2VsbF9kZW5zaXR5LCAiYmFjX2NlbGxfZGVuc2l0eS5vYmoiKQpgYGAKCgojIyMjIFszLjEuM10gRWNvcGxhdGUtYmFzZWQgTXVsdGlmdW5jdGlvbmFsaXR5ID0gUGhlbm90eXBpYyBNdWx0aWZ1bmN0aW9uYWxpdHkgKE1GX1ApCmBgYHtyfQpNRl9QIDwtIHJlYWRSRFMoIi4vSmFuMjAyNHYzL01GX2xpc3QvTUZfaW50ZWcxNF9hdmVfbWF0cml4X3Jhdy5vYmoiKQpoZWFkKE1GX1ApCmBgYAoKIyMjIyBbMy4xLjRdIENvbXBpbGVkIHNhbXBsZSBpbmZvLCBiZWZvcmUgY292ZXJhZ2UtYmFzZWQgc3RhbmRhcmRpemF0aW9uCkxpc3Qgb2YgQVNWIGNvbXBvc2l0aW9uIGJlZm9yZSBjb3ZlcmFnZS1iYXNlZCBzdGFuZGFyZGl6YXRpb24gYnV0IEFTVnMgZnJvbSBtaXRvY2hvbmRyaWEgYW5kIGNobG9yb3BsYXMgZXhjbHVkZWQKYGBge3J9CnJhd19wcm9rYXJ5b3RlX0FTVmNvbXBvc2l0aW9uX2luZm8gPC0gYXMuZGF0YS5mcmFtZSggcmVhZFJEUygiLi9KYW4yMDI0djMvQVNWX2NvbXBvc2l0aW9uL3RhYmxlX0FTVl9uby1taXRvY2hvbmRyaWEtbm8tY2hsb3JvcGxhc19iaXdha29fZGFkYTJfSmFuMjAyNC5vYmoiKSkKCiNUaGUgbnVtYmVyIG9mIEFTVnMgdGhhdCB3ZXJlIGRldGVjdGVkIGluIHR3byBuZWdhdGl2ZSBzYW1wbGVzCmFwcGx5KHJhd19wcm9rYXJ5b3RlX0FTVmNvbXBvc2l0aW9uX2luZm8gPiAwLCAxLCBzdW0pWzIxOjIyXQojVGhlIHRvdGFsIHJlYWRzIHRoYXQgd2VyZSBkZXRlY3RlZCBpbiB0d28gbmVnYXRpdmUgc2FtcGxlcwphcHBseShyYXdfcHJva2FyeW90ZV9BU1Zjb21wb3NpdGlvbl9pbmZvLCAxLCBzdW0pWzIxOjIyXQpgYGAKTGlzdCBvZiBzYW1wbGUgKGRhdGEgc2V0KSBpbmZvLCBiYWN0ZXJpYWwgYWJ1bmRhbmNlLCBzYW1wbGluZyBjb3ZlcmFnZSAoY292X2V4Y2x1KSwgI3JlYWRzIChzZXFfZXhjbHUpLCAjb2JzZXJ2ZWQgQVNWcyAocmljaF9leGNsdSkKYGBge3J9CmF0dHJpYnV0ZXNfc2FtcGxlIDwtIHJlYWRSRFMoIi4vSmFuMjAyNHYzL2F0dHJpX2V4Y2x1X3VuZGV0ZXIuZXVrYXJfSmFuMjAyNC5vYmoiKQphdHRyaWJ1dGVzX3NhbXBsZSRzYW1wbGVfSUQgPC0gYygiUzAxIiwgIlMwMiIsICJTMDMiLCAiUzA0IiwgIlMwNSIsICJTMDYiLCAiUzA3IiwgIlMwOCIsICJTMDkiLCAiUzEwIiwgIlMxMSIsICJTMTIiLCAiUzEzIiwgIlMxNCIsICJTMTUiLCAiUzE2IiwgIlMxNyIsICJTMTgiLCAiUzE5IiwgIlMyMCIpCmF0dHJpYnV0ZXNfc2FtcGxlWywgLWMoNCw1KV0gCmBgYAojIyMjIFszLjEuNV0gQVNWIGNvbXBvc2l0aW9uIHRhYmxlCkFTViB0YWJsZSBiZWluZyByYXJlZmllZCB3aXRoIHRoZSBjb3ZlcmFnZSA9IDAuOTIzMiBhbmQgdGhlbiBBU1ZzIHdpdGggMSkgcG9vciBhbGlnbm1lbnQgdG8gUGlDUlVTVDIgb3IgMikgd2l0aCAwIGFidW5kYW5jZSBiZWluZyBkZWxldGVkLCBub3RpbmcgdGhhdCB0aGUgZGF0YSBzZXRzIHdpdGggbG93IGNvdmVyYWdlcyB3ZXJlIGFsc28gZXhjbHVkZWQgYW5kIDEzIGRhdGEgc2V0cyByZW1haW5lZC4KYGBge3J9CnJlbWFpbmluZ19JRCA8LSBjKCJTMDEiLCAiUzAyIiwgIlMwMyIsICJTMDQiLCAiUzA1IiwgIlMwNiIsICJTMDciLCAiUzA4IiwgIlMxMSIsICJTMTciLCAiUzE4IiwgIlMxOSIsICJTMjAiKQpzdGFuZF9BU1ZfY29tIDwtIHJlYWRSRFMoIi4vSmFuMjAyNHYzL0FTVl9jb21wb3NpdGlvbi9Db21fcmFyZWZpZWRfZXhjbHVfdW5kZXRlci5ldWthcl9BZnRlck5lZ19maWx0ZXJlZF9vcmRlcl9kZWwwQVNWX0phbjIwMjQub2JqIikKY2xhc3Moc3RhbmRfQVNWX2NvbSkKY29sbmFtZXMoc3RhbmRfQVNWX2NvbSkKY29sbmFtZXMoc3RhbmRfQVNWX2NvbSkgPC0gcmVtYWluaW5nX0lECmhlYWQoc3RhbmRfQVNWX2NvbVssIDI6NV0pCmBgYAojIyMjIFszLjEuNl0gS08gY29tcG9zaXRpb24gdGFibGUgZm9yIGVhY2ggQVNWIHRoYXQgd2FzIGluY2x1ZGVkIGluICJzdGFuZF9BU1ZfY29tIi4KCmBgYHtyfQpLT19jb20gPC0gcmVhZFJEUygiLi9KYW4yMDI0djMvS09fY29tcG9zaXRpb24vS09fZXhjbHVfdW5kZXRlci5ldWthcl9BZnRlck5lZ19maWx0ZXJlZF9vcmRlcl9kZWwwQVNWX0phbjIwMjQub2JqIikKY2xhc3MoS09fY29tKQpoZWFkKEtPX2NvbSkKYGBgCgojIyMgWzMuMl0gRGF0YSBjb252ZXJzaW9uCiMjIyMgWzMuMi4xXSBCaW5hcml6YXRpb24KQmluYXJpemF0aW9uIG9mIEFTViBjb21wb3NpdGlvbiB3aXRoIHRoZSB0aHJlc2hvbGQgMC4wIGZvciBBU1ZzIGFuZCAxIGZvciBLT3MKYGBge3J9CiNjb3B5CnN0YW5kX0FTVl9jb21fYmluYXJpemVkIDwtIHN0YW5kX0FTVl9jb20KS09fY29tX2JpbmFyaXplZCA8LSBLT19jb20KCiNiaW5hcml6ZWQKc3RhbmRfQVNWX2NvbV9iaW5hcml6ZWRbc3RhbmRfQVNWX2NvbV9iaW5hcml6ZWQgPiAwXSA8LSAxLjAKc3RhbmRfQVNWX2NvbV9iaW5hcml6ZWRbc3RhbmRfQVNWX2NvbV9iaW5hcml6ZWQgPCAwXSA8LSAwLjAKCktPX2NvbV9iaW5hcml6ZWRbS09fY29tX2JpbmFyaXplZCA+PSAxLjBdIDwtIDEuMApLT19jb21fYmluYXJpemVkW0tPX2NvbV9iaW5hcml6ZWQgPCAxLjBdIDwtIDAuMApgYGAKCiMjIyMgWzMuMi4yXSBDYWxjdWxhdGluZyByaWNobmVzcyAKQVNWIGFuZCBLTyByaWNobmVzcyBmb3IgdGhlIHdob2xlIGRhdCBzZXRzCmBgYHtyfQpBU1ZfZ2FtbWFfcmljaG5lc3MgPC0gc3VtKGFwcGx5KHN0YW5kX0FTVl9jb21fYmluYXJpemVkLCAxLCBzdW0pID4gMCkKS09fZ2FtbWFfcmljaG5lc3MgPC0gc3VtKGFwcGx5KEtPX2NvbV9iaW5hcml6ZWQsIDIsIHN1bSkgPiAwKQpBU1ZfZ2FtbWFfcmljaG5lc3MKS09fZ2FtbWFfcmljaG5lc3MKYGBgCgpBU1YgYW5kIEtPIHJpY2huZXNzIGZvciBlYWNoIGRhdGEgc2V0CmBgYHtyfQpzdGFuZF9BU1ZfcmljaG5lc3MgPC0gYXBwbHkoc3RhbmRfQVNWX2NvbV9iaW5hcml6ZWQsIDIsIHN1bSkKS09fcmljaG5lc3MgPC0gbnVtZXJpYygxMykKZm9yKGogaW4gMToxMykgewogICNPYnRhaW4gdGhlIEtPIGNvbXBvc2l0aW9uIGZvciBlYWNoIGRhdGEgc2V0CiAgS09fbGlzdCA8LSB0KEtPX2NvbV9iaW5hcml6ZWQpICUqJSBzdGFuZF9BU1ZfY29tX2JpbmFyaXplZFssIGpdCiAgI0NhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIEtPcwogIEtPX3JpY2huZXNzW2pdIDwtIHN1bShLT19saXN0ID4gMCkKfQpNRl9QX2ZpbHRlcmVkMC4wNSA8LSBNRl9QWzIsIGMoMSwyLDMsNCw1LDYsNyw4LDExLDE3LDE4LDE5LDIwKV0gI3N1YnNldHMgb2Ygc2FtcGxlcyB0aGF0IGFyZSByZW1haW5pbmcgZm9yIGZ1cnRoZXIgYmlvaW5mb3JtYXRpYyBhbmFseXNlcwpwbG90KHN0YW5kX0FTVl9yaWNobmVzcywgS09fcmljaG5lc3MpCnBsb3Qoc3RhbmRfQVNWX3JpY2huZXNzLCBNRl9QX2ZpbHRlcmVkMC4wNSkKYGBgCgojIyMgWzMuM10gU3VtbWFyeSBvZiBkYXRhIHNldHMKClN1bW1hcml6aW5nIGJhc2ljIGluZm8gaW50byBhIGRhdGFmcmFtZQpgYGB7cn0KcmljaG5lc3NfdGVtcCA8LSBkYXRhLmZyYW1lKHNhbXBsZV9JRCA9IHJlbWFpbmluZ19JRCwgc3RhbmRfQVNWX3JpY2huZXNzLCBLT19yaWNobmVzcykKZGF0YV9zdW1tYXJ5IDwtIG1lcmdlKGF0dHJpYnV0ZXNfc2FtcGxlWywgLWMoNCw1KV0sIHJpY2huZXNzX3RlbXAsIGJ5ID0gInNhbXBsZV9JRCIsIGFsbCA9IFQpCmNvbG5hbWVzKGRhdGFfc3VtbWFyeSlbNDo3XSA8LSBjKCJiYWN0ZXJpYWwgYWJ1bmRhbmNlIiwgImNvdmVyYWdlIiwgIm5vX3JlYWRzIiwgIm9ic19BU1ZfcmljaG5lc3MiKQpkYXRhX3N1bW1hcnkgPC0gZGF0YS5mcmFtZShkYXRhX3N1bW1hcnksIE1GX1AwLjA1ID0gTUZfUFsyLCBdKQpkYXRhX3N1bW1hcnkKYGBgCgojIyBbNF0gUmVsYXRpb25zaGlwIGJldHdlZW4gQVNWIHJpY2huZXNzLCBLTyByaWNobmVzcywgYW5kIEVjb3BsYXRlIE11bHRpZnVuY3Rpb25hbGl0eQojIyMgWzQuMV0gRGF0YSBwcmVhcnJhbmdlbWVudApgYGB7cn0KcmljaG5lc3NfTUYgPC0gZGF0YS5mcmFtZShBU1ZfcmljaG5lc3MgPSBzdGFuZF9BU1ZfcmljaG5lc3MsIE1GX0cgPSBLT19yaWNobmVzcywgTUZfUDAuMDUgPSBNRl9QX2ZpbHRlcmVkMC4wNSwgbG9jYXRpb24gPSBkYXRhX3N1bW1hcnkkbG9jYXRpb25bYygxLDIsMyw0LDUsNiw3LDgsMTEsMTcsMTgsMTksMjApXSwgZGF0ZSA9IGRhdGFfc3VtbWFyeSRkYXRlX3NhbXBsZVtjKDEsMiwzLDQsNSw2LDcsOCwxMSwxNywxOCwxOSwyMCldKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIApyaWNobmVzc19NRgpgYGAKIyMjIFs0LjJdIEJhc2ljIHBsb3R0aW5nCmBgYHtyfQpwbG90KHJpY2huZXNzX01GKQpgYGAKIyMjIFs0LjNdIGxpbmVhciBtb2RlbApgYGB7cn0KbG1fbW9kZWwgPC0gbG0oTUZfUDAuMDUgfiBNRl9HLCBkYXRhID0gcmljaG5lc3NfTUYpCnN1bW1hcnkobG1fbW9kZWwpCnBsb3QoTUZfUDAuMDUgfiBNRl9HLCBkYXRhID0gcmljaG5lc3NfTUYpCmFibGluZShsbV9tb2RlbCkKCiNnbG0gYW5kIHN0ZXB3aXNlIG1vZGVsIHNlbGVjdGlvbgpzdW1tYXJ5KHN0ZXAoZ2xtKE1GX1AwLjA1IH4gTUZfRyArIEFTVl9yaWNobmVzcywgZGF0YSA9IHJpY2huZXNzX01GLCBmYW1pbHkgPSBwb2lzc29uKGxpbmsgPSAibG9nIikpKSkKCiNiZXN0CnogPC0gZ2xtKE1GX1AwLjA1IH4gTUZfRywgZGF0YSA9IHJpY2huZXNzX01GLCBmYW1pbHkgPSBwb2lzc29uKGxpbmsgPSAibG9nIikpCmBgYAojIyMjIFs0LjMuMV0gRmlndXJlIDEKYGBge3J9Cgp5X21heCA8LSAzNQpyaWNobmVzc19NRiRtZl9nID0gc2VxKDQ1MDAsIDczMDAsIGxlbmd0aC5vdXQgPSAxMykKcmljaG5lc3NfTUYkcHJlZGljdGVkID0gZXhwKHokY29lZmZpY2llbnRzWzFdICsgeiRjb2VmZmljaWVudHNbMl0gKiByaWNobmVzc19NRiRtZl9nKQpyaWNobmVzc19NRiRMb3cgPSByaWNobmVzc19NRiRwcmVkaWN0ZWQgLSAyICogc3FydChtZWFuKHJpY2huZXNzX01GJE1GX1AwLjA1KSkKcmljaG5lc3NfTUYkTG93W3JpY2huZXNzX01GJExvdyA8IDBdIDwtIDAKcmljaG5lc3NfTUYkSGlnaCA9IHJpY2huZXNzX01GJHByZWRpY3RlZCArIDIgKiBzcXJ0KG1lYW4ocmljaG5lc3NfTUYkTUZfUDAuMDUpKQpyaWNobmVzc19NRiRIaWdoW3JpY2huZXNzX01GJEhpZ2ggPiB5X21heF0gPC0geV9tYXgKCmxpbmVhcl9wbG90IDwtIGdncGxvdChkYXRhID0gcmljaG5lc3NfTUYpICsgZ2VvbV9wb2ludChhZXMoeCA9IE1GX0csIHkgPSBNRl9QMC4wNSwgc2hhcGUgPSByaWNobmVzc19NRiRsb2NhdGlvbiksIHNpemUgPSAzLCBhbHBoYSA9IDAuOSkgKyBsYWJzKHNoYXBlID0gInNpdGVzIikgKyBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygwLCAxLCAyLCA1LCA2KSkgCmxpbmVhcl9wbG90IDwtIGxpbmVhcl9wbG90ICsgZ2VvbV9saW5lKGFlcyh4ID0gbWZfZywgeSA9IHByZWRpY3RlZCkpCmxpbmVhcl9wbG90IDwtIGxpbmVhcl9wbG90ICsgZ2VvbV9yaWJib24oYWVzKHggPSBtZl9nLCB5bWluID0gTG93LCB5bWF4ID0gSGlnaCksIGFscGhhID0gMC4xKQpsaW5lYXJfcGxvdCA8LSBsaW5lYXJfcGxvdCArIHhsYWIoIk1GX0ciKSArIHlsYWIoIk1GX1AiKSArIHlsaW0oMCwgeV9tYXgpICsgdGhlbWVfYncoKSAKcGxvdChsaW5lYXJfcGxvdCkKYGBgClNhdmUgaXQgYXMgdGhlIHBkZiBmaWxlCmBgYHtyfQpwZGYoImZpZ3VyZTAxLnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDcsIG9uZWZpbGUgPSBGQUxTRSkKcGxvdChsaW5lYXJfcGxvdCkKIyBDbG9zZSB0aGUgUG9zdFNjcmlwdCBkZXZpY2UKZGV2Lm9mZigpCgpgYGAKCiMjIyMgWzQuMy4yXSBTdGF0aXN0aWNhbCB0ZXN0IHdoZW4gUzExIGRhdGEgaXMgZXhjbHVkZWQKYGBge3J9CiNnbG0gYW5kIHN0ZXB3aXNlIG1vZGVsIHNlbGVjdGlvbgpzdW1tYXJ5KHN0ZXAoZ2xtKE1GX1AwLjA1IH4gTUZfRyArIEFTVl9yaWNobmVzcywgZGF0YSA9IHJpY2huZXNzX01GWy05LCBdLCBmYW1pbHkgPSBwb2lzc29uKGxpbmsgPSAibG9nIikpKSkKYGBgCgoKIyMgWzVdIFNpbXVsYXRpb25zIGZvciBBU1YgZXh0aW5jdGlvbgojIyMgWzUuMV0gUmFuZG9tIGV4dGluY3Rpb24gKGFuYWx5dGljYWwgZm9ybXVsYXRpb24pClJlZjogQ09MV0VMTCBldCBhbC4gRWNvbG9neSwgODUoMTApLCAyMDA0LCBwcC4gMjcxNy0yNzI3CgpROiBIb3cgbWFueSBzcGVjaWVzIGhhdmUgZWFjaCBLTz8KCkE6IElubmVyIHByb2R1Y3Qgb2YgdGhlIHRyYW5zcG9zZWQgS08gdGFibGUgYW5kIEFTViB2ZWN0b3Igb2YgdGhlIHNwZWNpZmljIHNhbXBsZSByZXR1cm5zIHRoZSB2ZWN0b3IgcmVnYXJkaW5nIGhvdyBtYW55IHNwZWNpZXMgaGF2ZSBlYWNoIEtPCgojIyMjIFs1LjEuMV0gRGVmaW5pdGlvbiBvZiBmdW5jdGlvbnMgZm9yIGludGVycG9yYXRpb24KTm90ZTogbiEgPSBnYW1tYShuKzEpIGJ1dCBpdCBjYW5ub3QgYmUgZGlyZWN0bHkgdXNlZAoKYGBge3J9CmFscGhhX2poIDwtIGZ1bmN0aW9uKGosIGgsIEgpIHsKICB0ZW1wIDwtIDAuMAogIGlmKGogKyBoID4gSCkgewogICAgdGVtcCA8LSAwLjAKICB9IGVsc2UgewogICAgdGVtcCA8LSAxLjAKICAgIGZvcihrIGluIDA6KGggLSAxKSkgdGVtcCA8LSB0ZW1wKihIIC0gaiAtIGspLyhIIC0gaykKICB9CiAgcmV0dXJuKHRlbXApCn0KCnRhdV9jaGlyIDwtIGZ1bmN0aW9uKGgsIFNfb2JzLCBILCBzKXsKICB0ZW1wIDwtIFNfb2JzCiAgZm9yIChqIGluIDE6SCkgdGVtcCA8LSB0ZW1wIC0gYWxwaGFfamgoaiwgaCwgSCkqc1tqXTsKICByZXR1cm4odGVtcCkKfQpgYGAKCgojIyMjIFs1LjEuMl0gVHJpYWwgZm9yIGEgc2luZ2xlIHNhbXBsZSAoUzAyKQpgYGB7cn0KI0V4YW1wbGUgZm9yIGEgc2luZ2xlIHNhbXBsZQpLT19kaXN0IDwtIHQoS09fY29tX2JpbmFyaXplZCkgJSolIHN0YW5kX0FTVl9jb21fYmluYXJpemVkJFMwMgpoaXN0KEtPX2Rpc3QpCmBgYApJbmRleCBmb3IgaW50ZXJwb3JhdGlvbiBmdW5jdGlvbgpgYGB7cn0KcyA8LSB2ZWN0b3IoKSAjbnVtYmVyIG9mIEtPcyB3aXRoIGogdGltZSBhcHBlYXJhbmNlCmZvcihqIGluIDE6bWF4KEtPX2Rpc3QpKSB7CiAgc1tqXSA8LSBzdW0oS09fZGlzdCA9PSBqKQp9CmBgYAoKVHJpYWwgb2YgaW50ZXJwb3JhdGlvbiAocmFuZG9tIGV4dGluY3Rpb24pCmBgYHtyfQp0YXUgPC0gdmVjdG9yKCkKQVNWX3JpY2huZXNzXzAyIDwtIGRhdGFfc3VtbWFyeSRzdGFuZF9BU1ZfcmljaG5lc3NbMl0KS09fcmljaG5lc3NfMDIgPC0gZGF0YV9zdW1tYXJ5JEtPX3JpY2huZXNzWzJdCmZvcih4IGluIDE6QVNWX3JpY2huZXNzXzAyKSB0YXVbeF0gPC0gdGF1X2NoaXIoeCwgS09fcmljaG5lc3NfMDIsIEFTVl9yaWNobmVzc18wMiwgcykKcGxvdCgxOkFTVl9yaWNobmVzc18wMiwgdGF1KQpwbG90KGxvZzEwKDE6QVNWX3JpY2huZXNzXzAyKSwgbG9nMTAodGF1KSkKYGBgCkZpdHRpbmcgcG93ZXItbGF3IHJlZ3Jlc3Npb24gd2l0aCBkaWZmZXJlbmNlIHJhbmdlcyBhbmQgaW50ZXJ2YWwKYGBge3J9CnggPC0gMTpBU1ZfcmljaG5lc3NfMDIKI2Z1bGwgcmFuZ2Ugb2YgQVNWIHJpY2huZXNzIGFuZCB0aGUgZmluZSBpbnRlcnZhbCAKc3VtbWFyeShmaXRfZnVsbCA8LSBsbShmb3JtdWxhID0gbG9nMTAodGF1KSB+IGxvZzEwKHgpKSkKCiNGb3IgdGhlIGNvYXJzZSBpbnRlcnZhbCAoZXZlcnkgNSAlKQpzIDwtIEFTVl9yaWNobmVzc18wMi8yMApub19BU1YgPC0gdmVjdG9yKCkKbm9fQVNWWzFdIDwtIDEKZm9yKGsgaW4gMjoyMCkgbm9fQVNWW2tdIDwtIHJvdW5kKHMqKGsgLSAxKSkKbm9fQVNWWzIxXSA8LSBBU1ZfcmljaG5lc3NfMDIKCiNmdWxsIHJhbmdlIGFuZCBjb2Fyc2UgaW50ZXJ2YWwKc3VtbWFyeShmaXRfZnVsbF9jIDwtIGxtKGZvcm11bGEgPSBsb2cxMCh0YXVbbm9fQVNWXSkgfiBsb2cxMCh4W25vX0FTVl0pKSkKIzAtNTAlIHJlZHVjdGlvbiByYW5nZSBhbmQgdGhlIGZpbmUgaW50ZXJ2YWwKc3VtbWFyeShmaXRfNTAgPC0gbG0oZm9ybXVsYSA9IGxvZzEwKHRhdVtub19BU1ZbMTFdOkFTVl9yaWNobmVzc18wMl0pIH4gbG9nMTAoeFtub19BU1ZbMTFdOkFTVl9yaWNobmVzc18wMl0pKSkKIzAtNTAlIHJlZHVjdGlvbiByYW5nZSBhbmQgdGhlIGNvYXJzZSBpbnRlcnZhbApzdW1tYXJ5KGZpdF81MF9jIDwtIGxtKGZvcm11bGEgPSBsb2cxMCh0YXVbbm9fQVNWWzExOjIxXV0pIH4gbG9nMTAobm9fQVNWWzExOjIxXSkpKQojMC05MCUgcmVkdWN0aW9uIHJhbmdlIGFuZCB0aGUgZmluZSBpbnRlcnZhbApzdW1tYXJ5KGZpdF8xMCA8LSBsbShmb3JtdWxhID0gbG9nMTAodGF1W25vX0FTVlszXTpBU1ZfcmljaG5lc3NfMDJdKSB+IGxvZzEwKHhbbm9fQVNWWzNdOkFTVl9yaWNobmVzc18wMl0pKSkKIzAtOTAlIHJlZHVjdGlvbiByYW5nZSBhbmQgdGhlIGNvYXJzZSBpbnRlcnZhbApzdW1tYXJ5KGZpdF8xMF9jIDwtIGxtKGZvcm11bGEgPSBsb2cxMCh0YXVbbm9fQVNWWzM6MjFdXSkgfiBsb2cxMChub19BU1ZbMzoyMV0pKSkKCgpwbG90KGxvZzEwKHRhdSkgfiBsb2cxMCgxOkFTVl9yaWNobmVzc18wMiksIAogICAgIHhsaW0gPSBjKDAsIGxvZzEwKEFTVl9yaWNobmVzc18wMikpLCAKICAgICB5bGltID0gYygyLCBtYXgobG9nMTAodGF1KSkpLAogICAgIHhsYWIgPSAiTG9nMTAoQVNWIHJpY2huZXNzKSIsIAogICAgIHlsYWIgPSAiTG9nMTAoS08gcmljaG5lc3MpIiwKICAgICBtYWluID0gIkFuZSByaXZlciAyMDE5MDcwOSIKICAgICApCmFibGluZShmaXRfZnVsbCwgY29sID0gMiwgbHdkID0gMikKYWJsaW5lKGZpdF8xMCwgY29sID0gMywgbHdkID0gMikKYWJsaW5lKGZpdF81MCwgY29sID0gNCwgbHdkID0gMikKYWJsaW5lKGZpdF9mdWxsX2MsIGNvbCA9IDEsIGx0eSA9ICJkYXNoZWQiKQphYmxpbmUoZml0XzEwX2MsIGNvbCA9IDEsIGx0eSA9ICJkYXNoZWQiKQphYmxpbmUoZml0XzUwX2MsIGNvbCA9IDEsIGx0eSA9ICJkYXNoZWQiKQphYmxpbmUodiA9IGxvZzEwKG5vX0FTVlszXSksIGNvbCA9IDMsIGx0eSA9ICJkYXNoZWQiLCBsd2QgPSAyKQphYmxpbmUodiA9IGxvZzEwKG5vX0FTVlsxMV0pLCBjb2wgPSA0LCBsdHkgPSAiZGFzaGVkIiwgbHdkID0gMikKCmZpdHRlZF9tb2RlbCA8LSBmdW5jdGlvbih4KSB7CiAgdGVtcCA8LSAoMTBeZml0X2Z1bGwkY29lZmZpY2llbnRzWzFdKSooeF5maXRfZnVsbCRjb2VmZmljaWVudHNbMl0pCiAgcmV0dXJuKHRlbXApCn0gCnBsb3QoMTpBU1ZfcmljaG5lc3NfMDIsIHRhdSwgeGxpbSA9IGMoMSwgQVNWX3JpY2huZXNzXzAyKSwgeWxpbSA9IGMoMCwgbWF4KHRhdSkpKQpwYXIobmV3ID0gVCkKcGxvdCgxOkFTVl9yaWNobmVzc18wMiwgZml0dGVkX21vZGVsKHgpLCB4bGltID0gYygxLCBBU1ZfcmljaG5lc3NfMDIpLCB5bGltID0gYygwLCBtYXgodGF1KSksIHhsYWIgPSAiIiwgeWxhYiA9ICIiLCBjb2wgPSA0LCB0eXBlID0gImwiKQoKYGBgCgojIyMjIFs1LjEuM10gRm9yIGFsbCBzYW1wbGVzIHRvZ2V0aGVyCkRlZmluaXRpb24gb2YgZnVuY3Rpb24sIHdoaWNoIGhhcyB0aGUgYmluYXJpemVkIEFTViBjb21wb3NpdGlvbiBhbmQgdGhlIGJpbmFyaXplZCBLTyB0YWJsZSBhcyBwYXJhbWV0ZXJzCmBgYHtyfQpzYW1wbGVfSUQgPC0gYygxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCAxMSwgMTcsIDE4LCAxOSwgMjApICNvbmx5IGEgcGFydCBvZiBzYW1wbGVzIGlzIHVzZWQKcmFuZG9tX2V4dGluY3Rpb24gPC0gZnVuY3Rpb24oY29tX2JpbmFyaXplZCwgS09fYmluYXJpemVkKSB7CiAgQVNWX3JpY2huZXNzIDwtIHZlY3RvcigpCiAgS09fcmljaG5lc3MgPC0gdmVjdG9yKCkKICB0YXVfb25lIDwtIHZlY3RvcigpICNleHBlY3RlZCBLTyByaWNobmVzcyB3aXRoIGEgc2luZ2xlIEFTVgogIHNsb3BlX2Z1bGwgPC0gdmVjdG9yKCkgI3Nsb3BlIG9mIGZpdHRlZCBwb3dlciBsYXcKICBzbG9wZV9mdWxsX2MgPC0gdmVjdG9yKCkgI3Nsb3BlIG9mIGZpdHRlZCBwb3dlciBsYXcKICBzbG9wZV81MCA8LSB2ZWN0b3IoKSAjc2xvcGUgb2YgZml0dGVkIHBvd2VyIGxhdwogIHNsb3BlXzUwX2MgPC0gdmVjdG9yKCkgI3Nsb3BlIG9mIGZpdHRlZCBwb3dlciBsYXcKICBzbG9wZV8xMCA8LSB2ZWN0b3IoKSAjc2xvcGUgb2YgZml0dGVkIHBvd2VyIGxhdwogIHNsb3BlXzEwX2MgPC0gdmVjdG9yKCkgI3Nsb3BlIG9mIGZpdHRlZCBwb3dlciBsYXcKICAKICBzbG9wZV9mdWxsX3VwIDwtIHZlY3RvcigpICN1cHBlciBsaW1pdCBvZiA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbAogIHNsb3BlX2Z1bGxfZG93biA8LSB2ZWN0b3IoKSAjbG93ZXIgbGltaXQgb2YgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICBzbG9wZV9mdWxsX2NfdXAgPC0gdmVjdG9yKCkgI3VwcGVyIGxpbWl0IG9mIDk1JSBjb25maWRlbmNlIGludGVydmFsCiAgc2xvcGVfZnVsbF9jX2Rvd24gPC0gdmVjdG9yKCkgI2xvd2VyIGxpbWl0IG9mIDk1JSBjb25maWRlbmNlIGludGVydmFsCiAgc2xvcGVfNTBfdXAgPC0gdmVjdG9yKCkgI3VwcGVyIGxpbWl0IG9mIDk1JSBjb25maWRlbmNlIGludGVydmFsCiAgc2xvcGVfNTBfZG93biA8LSB2ZWN0b3IoKSAjbG93ZXIgbGltaXQgb2YgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICBzbG9wZV81MF9jX3VwIDwtIHZlY3RvcigpICN1cHBlciBsaW1pdCBvZiA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbAogIHNsb3BlXzUwX2NfZG93biA8LSB2ZWN0b3IoKSAjbG93ZXIgbGltaXQgb2YgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICBzbG9wZV8xMF91cCA8LSB2ZWN0b3IoKSAjdXBwZXIgbGltaXQgb2YgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICBzbG9wZV8xMF9kb3duIDwtIHZlY3RvcigpICNsb3dlciBsaW1pdCBvZiA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbAogIHNsb3BlXzEwX2NfdXAgPC0gdmVjdG9yKCkgI3VwcGVyIGxpbWl0IG9mIDk1JSBjb25maWRlbmNlIGludGVydmFsCiAgc2xvcGVfMTBfY19kb3duIDwtIHZlY3RvcigpICNsb3dlciBsaW1pdCBvZiA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbAoKICBpbnRlcmNlcHRfZnVsbCA8LSB2ZWN0b3IoKSAjaW50ZXJjZXB0IG9mIGZpdHRlZCBwb3dlciBsYXcgCiAgaW50ZXJjZXB0X2Z1bGxfYyA8LSB2ZWN0b3IoKSAjaW50ZXJjZXB0IG9mIGZpdHRlZCBwb3dlciBsYXcgCiAgaW50ZXJjZXB0XzUwIDwtIHZlY3RvcigpICNpbnRlcmNlcHQgb2YgZml0dGVkIHBvd2VyIGxhdyAKICBpbnRlcmNlcHRfNTBfYyA8LSB2ZWN0b3IoKSAjaW50ZXJjZXB0IG9mIGZpdHRlZCBwb3dlciBsYXcgCiAgaW50ZXJjZXB0XzEwIDwtIHZlY3RvcigpICNpbnRlcmNlcHQgb2YgZml0dGVkIHBvd2VyIGxhdyAKICBpbnRlcmNlcHRfMTBfYyA8LSB2ZWN0b3IoKSAjaW50ZXJjZXB0IG9mIGZpdHRlZCBwb3dlciBsYXcgCiAgCiAgUjJmaXR0ZWRfZnVsbCA8LSB2ZWN0b3IoKSAjYWRqdXN0ZWQgUi1zcXVhcmVkIHZhbHVlIG9mIGZpdHRlZCBwb3dlciBsYXcKICBSMmZpdHRlZF9mdWxsX2MgPC0gdmVjdG9yKCkgI2FkanVzdGVkIFItc3F1YXJlZCB2YWx1ZSBvZiBmaXR0ZWQgcG93ZXIgbGF3CiAgUjJmaXR0ZWRfNTAgPC0gdmVjdG9yKCkgI2FkanVzdGVkIFItc3F1YXJlZCB2YWx1ZSBvZiBmaXR0ZWQgcG93ZXIgbGF3CiAgUjJmaXR0ZWRfNTBfYyA8LSB2ZWN0b3IoKSAjYWRqdXN0ZWQgUi1zcXVhcmVkIHZhbHVlIG9mIGZpdHRlZCBwb3dlciBsYXcKICBSMmZpdHRlZF8xMCA8LSB2ZWN0b3IoKSAjYWRqdXN0ZWQgUi1zcXVhcmVkIHZhbHVlIG9mIGZpdHRlZCBwb3dlciBsYXcKICBSMmZpdHRlZF8xMF9jIDwtIHZlY3RvcigpICNhZGp1c3RlZCBSLXNxdWFyZWQgdmFsdWUgb2YgZml0dGVkIHBvd2VyIGxhdwogIAogIG5vX0FTViA8LSB2ZWN0b3IoKSAjQVNWIHJpY2huZXNzIHVzZWQgd2l0aCB0aGUgY29hcnNlIGludGVydmFsCiAgCiAgI0ZvciB0aGUgY29hcnNlIGludGVydmFsIChldmVyeSA1ICUpCiAKICBmb3Ioc2FtcGxlX25vIGluIDE6bGVuZ3RoKGNvbV9iaW5hcml6ZWRbMSxdKSl7CiAgICAjTnVtYmVyIG9mIEFTVnMgaGFyYm9yZWQgaW4gZWFjaCBLTwogICAgS09fZGlzdCA8LSB0KEtPX2JpbmFyaXplZCkgJSolIGNvbV9iaW5hcml6ZWRbLCBzYW1wbGVfbm9dCiAgICBzIDwtIHZlY3RvcigpICNudW1iZXIgb2YgS09zIHdpdGggaiB0aW1lIGFwcGVhcmFuY2UKICAgIGZvcihqIGluIDE6bWF4KEtPX2Rpc3QpKSB7CiAgICAgIHNbal0gPC0gc3VtKEtPX2Rpc3QgPT0gaikKICAgIH0gCiAgICAjQVNWIHJpY2huZXNzIGFuZCBLTyByaWNobmVzcwogICAgQVNWX3JpY2huZXNzW3NhbXBsZV9ub10gPC0gc3VtKGNvbV9iaW5hcml6ZWRbLCBzYW1wbGVfbm9dID4gMCkKICAgIEtPX3JpY2huZXNzW3NhbXBsZV9ub10gPC0gc3VtKEtPX2Rpc3QgPiAwKQogICAgCiAgICAjU2V0dGluZyBmb3IgdGhlIGNvYXJzZSBpbnRlcnZhbAogICAgaW50ZXJ2YWwgPC0gQVNWX3JpY2huZXNzW3NhbXBsZV9ub10vMjAgICAjZXZlcnkgNSUgY2hhbmdlcyBpbiBBU1YgcmljaG5lc3MKICAgIG5vX0FTVlsxXSA8LSAxCiAgICBmb3IoayBpbiAyOjIwKSBub19BU1Zba10gPC0gcm91bmQoaW50ZXJ2YWwqKGsgLSAxKSkKICAgIG5vX0FTVlsyMV0gPC0gQVNWX3JpY2huZXNzW3NhbXBsZV9ub10KCiAgICAjaW50ZXJwb2xhdGlvbgogICAgdGF1IDwtIHZlY3RvcigpCiAgICBmb3IoeCBpbiAxOkFTVl9yaWNobmVzc1tzYW1wbGVfbm9dKSB0YXVbeF0gPC0gdGF1X2NoaXIoeCwgS09fcmljaG5lc3Nbc2FtcGxlX25vXSwgQVNWX3JpY2huZXNzW3NhbXBsZV9ub10sIHMpCiAgICAKICAgICNTZXR0aW5nIGZvciBmaXR0aW5nIHBvd2VyIGxhdyAKICAgIGFzdiA8LSAxOkFTVl9yaWNobmVzc1tzYW1wbGVfbm9dCiAgICAKICAgICNmdWxsIHJhbmdlIG9mIEFTViByaWNobmVzcyBhbmQgdGhlIGZpbmUgaW50ZXJ2YWwgCiAgICBmaXRfZnVsbCA8LSBsbShmb3JtdWxhID0gbG9nMTAodGF1KSB+IGxvZzEwKGFzdikpCiAgICAjZnVsbCByYW5nZSBhbmQgY29hcnNlIGludGVydmFsCiAgICBmaXRfZnVsbF9jIDwtIGxtKGZvcm11bGEgPSBsb2cxMCh0YXVbbm9fQVNWXSkgfiBsb2cxMChhc3Zbbm9fQVNWXSkpCiAgICAjMC01MCUgcmVkdWN0aW9uIHJhbmdlIGFuZCB0aGUgZmluZSBpbnRlcnZhbAogICAgZml0XzUwIDwtIGxtKGZvcm11bGEgPSBsb2cxMCh0YXVbbm9fQVNWWzExXTpBU1ZfcmljaG5lc3Nbc2FtcGxlX25vXV0pIH4gbG9nMTAoYXN2W25vX0FTVlsxMV06QVNWX3JpY2huZXNzW3NhbXBsZV9ub11dKSkKICAgICMwLTUwJSByZWR1Y3Rpb24gcmFuZ2UgYW5kIHRoZSBjb2Fyc2UgaW50ZXJ2YWwKICAgIGZpdF81MF9jIDwtIGxtKGZvcm11bGEgPSBsb2cxMCh0YXVbbm9fQVNWWzExOjIxXV0pIH4gbG9nMTAobm9fQVNWWzExOjIxXSkpCiAgICAjMC05MCUgcmVkdWN0aW9uIHJhbmdlIGFuZCB0aGUgZmluZSBpbnRlcnZhbAogICAgZml0XzEwIDwtIGxtKGZvcm11bGEgPSBsb2cxMCh0YXVbbm9fQVNWWzNdOkFTVl9yaWNobmVzc1tzYW1wbGVfbm9dXSkgfiBsb2cxMChhc3Zbbm9fQVNWWzNdOkFTVl9yaWNobmVzc1tzYW1wbGVfbm9dXSkpCiAgICAjMC05MCUgcmVkdWN0aW9uIHJhbmdlIGFuZCB0aGUgY29hcnNlIGludGVydmFsCiAgICBmaXRfMTBfYyA8LSBsbShmb3JtdWxhID0gbG9nMTAodGF1W25vX0FTVlszOjIxXV0pIH4gbG9nMTAobm9fQVNWWzM6MjFdKSkKICAgICNEYXRhIHN1bW1hcnkKICAgIHRhdV9vbmVbc2FtcGxlX25vXSA8LSB0YXVbMV0KICAgIAogICAgc2xvcGVfZnVsbFtzYW1wbGVfbm9dIDwtIGZpdF9mdWxsJGNvZWZmaWNpZW50c1syXQogICAgc2xvcGVfZnVsbF9kb3duW3NhbXBsZV9ub10gPC0gY29uZmludC5sbShmaXRfZnVsbClbMiwgMV0KICAgIHNsb3BlX2Z1bGxfdXBbc2FtcGxlX25vXSA8LSBjb25maW50LmxtKGZpdF9mdWxsKVsyLCAyXQogICAgaW50ZXJjZXB0X2Z1bGxbc2FtcGxlX25vXSA8LSAxMF5maXRfZnVsbCRjb2VmZmljaWVudHNbMV0KICAgIFIyZml0dGVkX2Z1bGxbc2FtcGxlX25vXSA8LSBzdW1tYXJ5KGZpdF9mdWxsKSRhZGouci5zcXVhcmVkCiAgCiAgICBzbG9wZV9mdWxsX2Nbc2FtcGxlX25vXSA8LSBmaXRfZnVsbF9jJGNvZWZmaWNpZW50c1syXQogICAgc2xvcGVfZnVsbF9jX2Rvd25bc2FtcGxlX25vXSA8LSBjb25maW50LmxtKGZpdF9mdWxsX2MpWzIsIDFdCiAgICBzbG9wZV9mdWxsX2NfdXBbc2FtcGxlX25vXSA8LSBjb25maW50LmxtKGZpdF9mdWxsX2MpWzIsIDJdCiAgICBpbnRlcmNlcHRfZnVsbF9jW3NhbXBsZV9ub10gPC0gMTBeZml0X2Z1bGxfYyRjb2VmZmljaWVudHNbMV0KICAgIFIyZml0dGVkX2Z1bGxfY1tzYW1wbGVfbm9dIDwtIHN1bW1hcnkoZml0X2Z1bGxfYykkYWRqLnIuc3F1YXJlZAogICAgCiAgICBzbG9wZV81MFtzYW1wbGVfbm9dIDwtIGZpdF81MCRjb2VmZmljaWVudHNbMl0KICAgIHNsb3BlXzUwX2Rvd25bc2FtcGxlX25vXSA8LSBjb25maW50LmxtKGZpdF81MClbMiwgMV0KICAgIHNsb3BlXzUwX3VwW3NhbXBsZV9ub10gPC0gY29uZmludC5sbShmaXRfNTApWzIsIDJdCiAgICBpbnRlcmNlcHRfNTBbc2FtcGxlX25vXSA8LSAxMF5maXRfNTAkY29lZmZpY2llbnRzWzFdCiAgICBSMmZpdHRlZF81MFtzYW1wbGVfbm9dIDwtIHN1bW1hcnkoZml0XzUwKSRhZGouci5zcXVhcmVkCiAgICAKICAgIHNsb3BlXzUwX2Nbc2FtcGxlX25vXSA8LSBmaXRfNTBfYyRjb2VmZmljaWVudHNbMl0KICAgIHNsb3BlXzUwX2NfZG93bltzYW1wbGVfbm9dIDwtIGNvbmZpbnQubG0oZml0XzUwX2MpWzIsIDFdCiAgICBzbG9wZV81MF9jX3VwW3NhbXBsZV9ub10gPC0gY29uZmludC5sbShmaXRfNTBfYylbMiwgMl0KICAgIGludGVyY2VwdF81MF9jW3NhbXBsZV9ub10gPC0gMTBeZml0XzUwX2MkY29lZmZpY2llbnRzWzFdCiAgICBSMmZpdHRlZF81MF9jW3NhbXBsZV9ub10gPC0gc3VtbWFyeShmaXRfNTBfYykkYWRqLnIuc3F1YXJlZAogICAgCiAgICBzbG9wZV8xMFtzYW1wbGVfbm9dIDwtIGZpdF8xMCRjb2VmZmljaWVudHNbMl0KICAgIHNsb3BlXzEwX2Rvd25bc2FtcGxlX25vXSA8LSBjb25maW50LmxtKGZpdF8xMClbMiwgMV0KICAgIHNsb3BlXzEwX3VwW3NhbXBsZV9ub10gPC0gY29uZmludC5sbShmaXRfMTApWzIsIDJdCiAgICBpbnRlcmNlcHRfMTBbc2FtcGxlX25vXSA8LSAxMF5maXRfMTAkY29lZmZpY2llbnRzWzFdCiAgICBSMmZpdHRlZF8xMFtzYW1wbGVfbm9dIDwtIHN1bW1hcnkoZml0XzEwKSRhZGouci5zcXVhcmVkCiAgICAKICAgIHNsb3BlXzEwX2Nbc2FtcGxlX25vXSA8LSBmaXRfMTBfYyRjb2VmZmljaWVudHNbMl0KICAgIHNsb3BlXzEwX2NfZG93bltzYW1wbGVfbm9dIDwtIGNvbmZpbnQubG0oZml0XzEwX2MpWzIsIDFdCiAgICBzbG9wZV8xMF9jX3VwW3NhbXBsZV9ub10gPC0gY29uZmludC5sbShmaXRfMTBfYylbMiwgMl0KICAgIGludGVyY2VwdF8xMF9jW3NhbXBsZV9ub10gPC0gMTBeZml0XzEwX2MkY29lZmZpY2llbnRzWzFdCiAgICBSMmZpdHRlZF8xMF9jW3NhbXBsZV9ub10gPC0gc3VtbWFyeShmaXRfMTBfYykkYWRqLnIuc3F1YXJlZAogICAgCiAgICAjbG9nMTAtbG9nMTAgc2NhbGUgZml0dGluZyAKICAgIHBsb3QobG9nMTAoYXN2KSwgbG9nMTAodGF1KSwgbWFpbiA9IHNhbXBsZV9pbmZvJERlc2NyaXB0aW9uW3NhbXBsZV9JRFtzYW1wbGVfbm9dXSwgeGxpbSA9IGMoMCwgbG9nMTAoQVNWX3JpY2huZXNzW3NhbXBsZV9ub10pKSwgeWxpbSA9IGMoMi41LCBsb2cxMChtYXgodGF1KSkpKQogICAgYWJsaW5lKGZpdF9mdWxsLCBjb2wgPSAyLCBsd2QgPSAyKQogICAgYWJsaW5lKGZpdF8xMCwgY29sID0gMywgbHdkID0gMikKICAgIGFibGluZShmaXRfNTAsIGNvbCA9IDQsIGx3ZCA9IDIpCiAgICBhYmxpbmUoZml0X2Z1bGxfYywgY29sID0gMSwgbHR5ID0gImRhc2hlZCIpCiAgICBhYmxpbmUoZml0XzEwX2MsIGNvbCA9IDEsIGx0eSA9ICJkYXNoZWQiKQogICAgYWJsaW5lKGZpdF81MF9jLCBjb2wgPSAxLCBsdHkgPSAiZGFzaGVkIikKICAgIGFibGluZSh2ID0gbG9nMTAobm9fQVNWWzNdKSwgY29sID0gMywgbHR5ID0gImRhc2hlZCIsIGx3ZCA9IDIpCiAgICBhYmxpbmUodiA9IGxvZzEwKG5vX0FTVlsxMV0pLCBjb2wgPSA0LCBsdHkgPSAiZGFzaGVkIiwgbHdkID0gMikKICAgIAogICAgaWYoc2FtcGxlX25vID09IDEpIHsKICAgICAgcGRmKCJmaWd1cmUwMmEucGRmIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNywgb25lZmlsZSA9IEZBTFNFKQogICAgICBwbG90KGxvZzEwKGFzdiksIGxvZzEwKHRhdSksIG1haW4gPSBzYW1wbGVfaW5mbyREZXNjcmlwdGlvbltzYW1wbGVfSURbc2FtcGxlX25vXV0sIHhsaW0gPSBjKDAsIGxvZzEwKEFTVl9yaWNobmVzc1tzYW1wbGVfbm9dKSksIHlsaW0gPSBjKDIuNSwgbG9nMTAobWF4KHRhdSkpKSkKICAgICAgYWJsaW5lKGZpdF9mdWxsLCBjb2wgPSAyLCBsd2QgPSAyKQogICAgICBhYmxpbmUoZml0XzEwLCBjb2wgPSAzLCBsd2QgPSAyKQogICAgICBhYmxpbmUoZml0XzUwLCBjb2wgPSA0LCBsd2QgPSAyKQogICAgICBhYmxpbmUoZml0X2Z1bGxfYywgY29sID0gMSwgbHR5ID0gImRhc2hlZCIpCiAgICAgIGFibGluZShmaXRfMTBfYywgY29sID0gMSwgbHR5ID0gImRhc2hlZCIpCiAgICAgIGFibGluZShmaXRfNTBfYywgY29sID0gMSwgbHR5ID0gImRhc2hlZCIpCiAgICAgIGFibGluZSh2ID0gbG9nMTAobm9fQVNWWzNdKSwgY29sID0gMywgbHR5ID0gImRhc2hlZCIsIGx3ZCA9IDIpCiAgICAgIGFibGluZSh2ID0gbG9nMTAobm9fQVNWWzExXSksIGNvbCA9IDQsIGx0eSA9ICJkYXNoZWQiLCBsd2QgPSAyKQogICAgICAjIENsb3NlIHRoZSBQb3N0U2NyaXB0IGRldmljZQogICAgICBkZXYub2ZmKCkKICAgIH0KICB9ICAKICAjU3VtbWFyaXppbmcgcmVzdWx0cyBpbnRvIGRhdGFmcmFtZQogIHN1bW1hcnlfcmFuZG9tX2V4dCA8LSBkYXRhLmZyYW1lKAogICAgc2FtcGxlID0gc2FtcGxlX2luZm8kRGVzY3JpcHRpb25bc2FtcGxlX0lEXSwgQVNWX3JpY2huZXNzLCBLT19yaWNobmVzcywgCiAgICB0YXVfb25lLCAKICAgIGludGVyY2VwdF9mdWxsLCBpbnRlcmNlcHRfZnVsbF9jLCBpbnRlcmNlcHRfNTAsIGludGVyY2VwdF81MF9jLCBpbnRlcmNlcHRfMTAsIGludGVyY2VwdF8xMF9jLAogICAgc2xvcGVfZnVsbCwgc2xvcGVfZnVsbF9jLCBzbG9wZV81MCwgc2xvcGVfNTBfYywgc2xvcGVfMTAsIHNsb3BlXzEwX2MsCiAgICBzbG9wZV9mdWxsX2Rvd24sIHNsb3BlX2Z1bGxfY19kb3duLCBzbG9wZV81MF9kb3duLCBzbG9wZV81MF9jX2Rvd24sIHNsb3BlXzEwX2Rvd24sIHNsb3BlXzEwX2NfZG93biwKICAgIHNsb3BlX2Z1bGxfdXAsIHNsb3BlX2Z1bGxfY191cCwgc2xvcGVfNTBfdXAsIHNsb3BlXzUwX2NfdXAsIHNsb3BlXzEwX3VwLCBzbG9wZV8xMF9jX3VwLAogICAgUjJmaXR0ZWRfZnVsbCwgUjJmaXR0ZWRfZnVsbF9jLCBSMmZpdHRlZF81MCwgUjJmaXR0ZWRfNTBfYywgUjJmaXR0ZWRfMTAsIFIyZml0dGVkXzEwX2MKICApCiAgCiAgcmV0dXJuKHN1bW1hcnlfcmFuZG9tX2V4dCkKfQoKYGBgClVzaW5nIHRoZSBBU1YgdGFibGUgd2l0aG91dCBjb252ZXJ0aW5nIGJ5IGJhY3RlcmlhbCBkaXJlY3QgY291bnQKYGBge3J9CnJhbmRvbV9hbmFseXRpY2FsIDwtIHJhbmRvbV9leHRpbmN0aW9uKHN0YW5kX0FTVl9jb21fYmluYXJpemVkLCBLT19jb21fYmluYXJpemVkKQpyYW5kb21fYW5hbHl0aWNhbApgYGAKVmFyaWF0aW9ucyBiZXR3ZWVuIHNhbXBsZXPjgIAoRmlndXJlIDJiKQpgYGB7cn0KI3Bsb3QocmFuZG9tX2FuYWx5dGljYWxbLCBdKQphc3ZfcmVkdW5kYW5jeSA8LSBsbShzbG9wZV8xMF9jIH4gQVNWX3JpY2huZXNzLCBkYXRhID0gcmFuZG9tX2FuYWx5dGljYWwpCnN1bW1hcnkoYXN2X3JlZHVuZGFuY3kpCnBsb3QoCiAgc2xvcGVfMTBfYyB+IEFTVl9yaWNobmVzcywgZGF0YSA9IHJhbmRvbV9hbmFseXRpY2FsLAogIHBjaCA9IGMoMCwxLDIsNSw2KVthcy5mYWN0b3IoYXR0cmlidXRlc19zYW1wbGUkbG9jYXRpb25bc2FtcGxlX0lEXSldLAogIGNvbCA9IGMoMSwyLDMsNCw1LDYpW2FzLmZhY3RvcihhdHRyaWJ1dGVzX3NhbXBsZSRkYXRlX3NhbXBsZVtzYW1wbGVfSURdKV0sCiAgeGxhYiA9ICJBU1YgcmljaG5lc3MiLCB5bGFiID0gIm11bHRpZnVuY3Rpb25hbCByZWR1bmRhbmN5IGV4cG9uZW50IChhKSIsCiAgeWxpbSA9IGMoMC4wNiwgMC4xNikKKQphYmxpbmUoYXN2X3JlZHVuZGFuY3kpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBsZXZlbHMoYXMuZmFjdG9yKGF0dHJpYnV0ZXNfc2FtcGxlJGxvY2F0aW9uKSksIHBjaCA9IGMoMCwxLDIsNSw2KSkKbGVnZW5kKCJib3R0b21sZWZ0IiwgbGVnZW5kID0gbGV2ZWxzKGFzLmZhY3RvcihhdHRyaWJ1dGVzX3NhbXBsZSRkYXRlX3NhbXBsZVtzYW1wbGVfSURdKSksIGNvbCA9IGMoMSwyLDMsNCw1LDYpLCBwY2ggPSBjKDEsMSwxLDEsMSwxKSkKI3RleHQocmFuZG9tX3Jlc3VsdCRBU1ZfcmljaG5lc3MsIHJhbmRvbV9yZXN1bHQkc2xvcGUsbGFiZWxzID0gYXR0cmlidXRlc19zYW1wbGUkbG9jYXRpb25bc2FtcGxlX0lEXSwgY2V4ID0gMC42LCBwb3MgPSA0LCBhZGogPSAxKQpgYGAKYGBge3J9CnBkZigiZmlndXJlMDJiLnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDcsIG9uZWZpbGUgPSBGQUxTRSkKCnBsb3QoCiAgc2xvcGVfMTBfYyB+IEFTVl9yaWNobmVzcywgZGF0YSA9IHJhbmRvbV9hbmFseXRpY2FsLAogIHBjaCA9IGMoMCwxLDIsNSw2KVthcy5mYWN0b3IoYXR0cmlidXRlc19zYW1wbGUkbG9jYXRpb25bc2FtcGxlX0lEXSldLAogIGNvbCA9IGMoMSwyLDMsNCw1LDYpW2FzLmZhY3RvcihhdHRyaWJ1dGVzX3NhbXBsZSRkYXRlX3NhbXBsZVtzYW1wbGVfSURdKV0sCiAgeGxhYiA9ICJBU1YgcmljaG5lc3MiLCB5bGFiID0gIm11bHRpZnVuY3Rpb25hbCByZWR1bmRhbmN5IGV4cG9uZW50IChhKSIsCiAgeWxpbSA9IGMoMC4wNiwgMC4xNikKKQphYmxpbmUoYXN2X3JlZHVuZGFuY3kpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBsZXZlbHMoYXMuZmFjdG9yKGF0dHJpYnV0ZXNfc2FtcGxlJGxvY2F0aW9uKSksIHBjaCA9IGMoMCwxLDIsNSw2KSkKbGVnZW5kKCJib3R0b21sZWZ0IiwgbGVnZW5kID0gbGV2ZWxzKGFzLmZhY3RvcihhdHRyaWJ1dGVzX3NhbXBsZSRkYXRlX3NhbXBsZVtzYW1wbGVfSURdKSksIGNvbCA9IGMoMSwyLDMsNCw1LDYpLCBwY2ggPSBjKDEsMSwxLDEsMSwxKSkKCiMgQ2xvc2UgdGhlIFBvc3RTY3JpcHQgZGV2aWNlCmRldi5vZmYoKQoKYGBgCgoKIyMjIyMgWzUuMS4zJ10gV2hlbiBTMTEgaXMgZXhjbHVkZWQKYGBge3J9CmFzdl9yZWR1bmRhbmN5MiA8LSBsbShzbG9wZV8xMF9jIH4gQVNWX3JpY2huZXNzLCBkYXRhID0gcmFuZG9tX2FuYWx5dGljYWxbLTksIF0pCnN1bW1hcnkoYXN2X3JlZHVuZGFuY3kyKQpgYGAKCgojIyMjIFs1LjEuNF0gTm90ZSBmb3IgdGhlIHNsb3BlIGZyb20gcmFuZG9tIGV4dGluY3Rpb24KVGhlIHNsb3BlIHdhcyBtdWNoIHNoYWxsb3dlciB0aGFuIHRob3NlIGZyb20gTWlraSBldCBhbC4gMjAxNC4gVGhpcyBpcyBwcm9iYWJseSBiZWNhdXNlIHRoZSB1bml0IG9mIGV4dGluY3Rpb24gaXMgQVNWIGJ1dCBub3QgdGhlIE9UVSBvciBzcGVjaWVzLiBXaGVuIHRoZSB1bml0IG9mIGV4dGluY3Rpb24gaWYgQVNWLCB0aGUgZnVuY3Rpb25hbCByZWR1bmRhbmN5IHNob3VsZCBiZSBtdWNoIGdyZWF0ZXIgdGhhbiB0aG9zZSBiZXR3ZWVuIE9UVXMgb3Igc3BlY2llcy4gSW4gTWlraSBldCBhbC4gMjAxNCwgaW4gbW9zdCBvZiBzaW11bGF0aW9ucywgd2UgdXNlZCB0aGUgcHNldWRvLWNvbW11bml0aWVzIHdoZXJlIHNpbmdsZSBzcGVjaWVzIGZyb20gYSBnZW51cyB3YXMgaW5jbHVkZWQuIAoKIyMjIFs1LjJdIE5vbi1yYW5kb20gZXh0aW5jdGlvbiBzY2VuYXJpb3MKS2V5d29yZHM6IGZ1bmN0aW9uYWwgcmVkdW5kYW5jeSBhbmQgZnVuY3Rpb25hbCB2dWxuZXJhYmlsaXR5CgojIyMjIFs1LjIuMV0gTG9hZGluZyB0aGUgc3Vydml2YWwgcHJvYmFiaWxpdHkgbGlzdApgYGB7cn0Kc3Vydml2YWxfcmF0ZSA8LSByZWFkUkRTKCIuL0phbjIwMjR2My9zdXJ2aXZhbF9yYXRlL3N1cnZpYWxfcmF0ZV9kZWwwQVNWX2V4Y2x1X3VuZGV0ZXIuZXVrYXJfQWZ0ZXJOZWdfSmFuMjAyNC5vYmoiKQojYWRkaW5nIHJhbmRvbSBjYXNlCnN1cnZpdmFsX3JhdGVfbW9kIDwtIGRhdGEuZnJhbWUocmFuZG9tID0gcmVwKDEsIGxlbmd0aChzdXJ2aXZhbF9yYXRlWywgMV0pKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRjEgPSBzdXJ2aXZhbF9yYXRlJEtPX25vX3BhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGMiA9IHN1cnZpdmFsX3JhdGUkS09fbm9fcGFfaW52ZXJzZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGMyA9IHN1cnZpdmFsX3JhdGUkZGlzdF9LT19wYV9tZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEY0ID0gc3Vydml2YWxfcmF0ZSRkaXN0X0tPX3BhX21lYW5faW52ZXJzZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBMSA9IHN1cnZpdmFsX3JhdGUkYWJ1bmRhbmNlX21lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQTIgPSBzdXJ2aXZhbF9yYXRlJGFidW5kYW5jZV9pbnZlcnNlX3NkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEEzID0gc3Vydml2YWxfcmF0ZSRhYnVuZGFuY2VfcmljaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBNCA9IHN1cnZpdmFsX3JhdGUkYWJ1bmRhbmNlX3NoYQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKYGBgCgojIyMjIFs1LjIuMl0gVHJpYWwgb2YgcmVzYW1wbGluZyB3aXRoIHdlaWdodGVkIHByb2JhYmlsaXR5CkF0IGVhY2ggbGV2ZWwgb2YgQVNWIHJpY2huZXNzLCBjYWxjdWxhdGluZyB0aGUgYXZlcmFnZXMgZnJvbSByZXBldGl0aW9uIGZpcnN0IGFuZCBtYWtlIGEgc2luZ2xlIGxpbmUgd2l0aCBhdmVyYWdlcwpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQojZm9yIHNhbXBsZV8xCnByZXNlbmNlIDwtIHdoaWNoKHN0YW5kX0FTVl9jb21fYmluYXJpemVkJFMwMSA+IDApCiNBU1Ygd2l0aCBncmVhdGVyIHJpY2huZXNzIG9mIEtPcyAobG9uZ2VyIGdlbm9tZXMpIGhhcyBhIGhpZ2hlciBzdXJ2aXZhbCBwcm9iYWJpbGl0eQpwcm9iX3Rlc3QgPC0gcHJvcC50YWJsZShzdXJ2aXZhbF9yYXRlX21vZCRGMVtwcmVzZW5jZV0pCkFTVl9yaWNobmVzcyA8LSBsZW5ndGgocHJlc2VuY2UpCm5vX3JlcGV0aXRpb24gPC0gMTAKQVNWcyA8LSBudW1lcmljKDIxKQpLT3MgPC0gbnVtZXJpYygyMSkKS09zX3RlbXAgPC0gbnVtZXJpYyhub19yZXBldGl0aW9uKQpzdXJ2aXZlZF9BU1ZzIDwtIGxpc3QoKQpBU1ZzX2Z1bGwgPC0gQVNWX3JpY2huZXNzCktPc19mdWxsIDwtIHJpY2huZXNzX01GJE1GX0cKc3Vydml2ZWRfQVNWcyA8LSBsaXN0KCkKcyA8LSBBU1ZfcmljaG5lc3MvMjAKc2xvcGUgPC0gbnVtZXJpYyhub19yZXBldGl0aW9uKQoKI1ByZXBhcmluZyBzdXJ2aXZhbCBzZXF1ZW5jZXMKZm9yKGogaW4gMTpub19yZXBldGl0aW9uKSB7CiAgI2Z1bGx5IHNodWZmbGluZyBmb3IgdGhlIG9yZGVyIG9mIHN1cnZpdmFsICh0aGUgaW52ZXJzZSBvcmRlciBvZiBleHRpbmN0aW9uKQogIHN1cnZpdmVkX0FTVnNbW2pdXSA8LSBzYW1wbGUoMTpBU1ZfcmljaG5lc3MsIHNpemUgPSBBU1ZfcmljaG5lc3MsIHJlcGxhY2UgPSBGQUxTRSwgcHJvYiA9IHByb2JfdGVzdCkKICAjc3Vydml2ZWRfQVNWc1tbal1dIDwtIHNhbXBsZSgxOmxlbmd0aChwcmVzZW5jZSksIHNpemUgPSBsZW5ndGgocHJlc2VuY2UpLCByZXBsYWNlID0gRkFMU0UpCn0KCiNGb3IgcGxvdHRpbmcgZWFjaCBzdXJ2aXZhbCBzZXF1ZW5jZQpmb3IoaiBpbiAxOm5vX3JlcGV0aXRpb24pIHsKICAjVGhlIGNhc2Ugd2l0aCBhIHNpbmdsZSBBU1YKICBBU1ZzWzFdIDwtIDEKICBLT19saXN0X3N1cnZpdmVkIDwtIEtPX2NvbV9iaW5hcml6ZWRbc3Vydml2ZWRfQVNWc1tbal1dWzFdLCBdCiAgS09zWzFdIDwtIHN1bShLT19saXN0X3N1cnZpdmVkID4gMCkKICBmb3IoayBpbiAyOjIwKSB7CiAgICBzdXJ2aXZlZF9yaWNobmVzcyA8LSByb3VuZChzKihrIC0gMSkpCiAgICBBU1ZzW2tdIDwtIHN1cnZpdmVkX3JpY2huZXNzCiAgICBLT19zdXJ2aXZlZCA8LSBLT19jb21fYmluYXJpemVkW3ByZXNlbmNlW3N1cnZpdmVkX0FTVnNbW2pdXVsxOnN1cnZpdmVkX3JpY2huZXNzXV0sIF0KICAgIEtPX2xpc3Rfc3Vydml2ZWQgPC0gYXBwbHkoS09fc3Vydml2ZWQsIDIsIHN1bSkKICAgIEtPc1trXSA8LSBzdW0oS09fbGlzdF9zdXJ2aXZlZCA+IDApCiAgfQogICNUaGUgY2FzZSB3aXRoIGFsbCBBU1ZzCiAgayA8LSAyMQogIEFTVnNba10gPC0gQVNWc19mdWxsCiAgS09zW2tdIDwtIEtPc19mdWxsCiAgCiAgZml0dGVkX3Bvd2VyIDwtIGxtKGZvcm11bGEgPSBsb2cxMChLT3MpIH4gbG9nMTAoQVNWcykpCiAgc2xvcGVbal0gPC0gZml0dGVkX3Bvd2VyJGNvZWZmaWNpZW50c1syXQogIAogIHBsb3QobG9nMTAoS09zKSB+IGxvZzEwKEFTVnMpICwgdHlwZSA9ICJsIiwgeGxpbSA9IGMobG9nMTAoMSksIGxvZzEwKEFTVnNbMjFdKSksIHlsaW0gPSBjKGxvZzEwKDEwMCksIGxvZzEwKEtPc1syMV0pKSwgY29sID0gOCkKICBwYXIobmV3ID0gVCkKICAjcHJpbnQoaikKfQoKI0ZvciBwbG90dGluZyB3aXRoIGF2ZXJhZ2luZyBLT3MgYXQgZWFjaCBzdXJ2aXZhbCBsZXZlbAojVGhlIGNhc2Ugd2l0aCBhIHNpbmdsZSBBU1YKQVNWc1sxXSA8LSAxCmZvcihqIGluIDE6bm9fcmVwZXRpdGlvbikgewogIEtPX2xpc3Rfc3Vydml2ZWQgPC0gS09fY29tX2JpbmFyaXplZFtzdXJ2aXZlZF9BU1ZzW1tqXV1bMV0sIF0KICBLT3NfdGVtcFtqXSA8LSBzdW0oS09fbGlzdF9zdXJ2aXZlZCA+IDApCn0KS09zWzFdIDwtIG1lYW4oS09zX3RlbXApCmZvcihrIGluIDI6MjApIHsKICBzdXJ2aXZlZF9yaWNobmVzcyA8LSByb3VuZChzKihrIC0gMSkpCiAgQVNWc1trXSA8LSBzdXJ2aXZlZF9yaWNobmVzcwogIGZvcihqIGluIDE6bm9fcmVwZXRpdGlvbikgewogICAgS09fc3Vydml2ZWQgPC0gS09fY29tX2JpbmFyaXplZFtwcmVzZW5jZVtzdXJ2aXZlZF9BU1ZzW1tqXV1bMTpzdXJ2aXZlZF9yaWNobmVzc11dLCBdCiAgICBLT19saXN0X3N1cnZpdmVkIDwtIGFwcGx5KEtPX3N1cnZpdmVkLCAyLCBzdW0pCiAgICBLT3NfdGVtcFtqXSA8LSBzdW0oS09fbGlzdF9zdXJ2aXZlZCA+IDApICAgIAogIH0KICBLT3Nba10gPC0gbWVhbihLT3NfdGVtcCkKfQoKCmsgPC0gMjEKQVNWc1trXSA8LSBBU1ZzX2Z1bGwKS09zW2tdIDwtIEtPc19mdWxsCgpmaXR0ZWRfcG93ZXIgPC0gbG0oZm9ybXVsYSA9IGxvZzEwKEtPcykgfiBsb2cxMChBU1ZzKSkKc2xvcGUgPC0gZml0dGVkX3Bvd2VyJGNvZWZmaWNpZW50c1syXQogIApwbG90KGxvZzEwKEtPcykgfiBsb2cxMChBU1ZzKSAsIHR5cGUgPSAiYiIsIHhsaW0gPSBjKGxvZzEwKDEpLCBsb2cxMChBU1ZzWzIxXSkpLCB5bGltID0gYyhsb2cxMCgxMDApLCBsb2cxMChLT3NbMjFdKSksIGNleCA9IDIsIGNvbCA9IDQsIG1haW4gPSAiU21hbGxlciBLTyByaWNobmVzcyBnb2VzIGV4dGluY3QgZWFybGllciIpCiNwcmludChqKQpjb25maW50LmxtKGZpdHRlZF9wb3dlcikKYGBgCiMjIyMgWzUuMi4zXSBTaW11bGF0aW9ucyBmb3IgYSBzcGVjaWZpYyBkYXRhIHNldCB3aXRoIGFsbCBzY2VuYXJpb3MKQXQgZWFjaCBsZXZlbCBvZiBBU1YgcmljaG5lc3MsIGNhbGN1bGF0aW5nIHRoZSBhdmVyYWdlcyBmcm9tIHJlcGV0aXRpb24gZmlyc3QgYW5kIG1ha2UgYSBzaW5nbGUgbGluZSB3aXRoIGF2ZXJhZ2VzCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9CiNmb3Igc2FtcGxlXzAxCnByZXNlbmNlIDwtIHdoaWNoKHN0YW5kX0FTVl9jb21fYmluYXJpemVkJFMwMSA+IDApCiNBU1Ygd2l0aCBncmVhdGVyIHJpY2huZXNzIG9mIEtPcyAobG9uZ2VyIGdlbm9tZXMpIGhhcyBhIGhpZ2hlciBzdXJ2aXZhbCBwcm9iYWJpbGl0eQoKQVNWX3JpY2huZXNzIDwtIGxlbmd0aChwcmVzZW5jZSkKbm9fcmVwZXRpdGlvbiA8LSAxMDAKQVNWcyA8LSBudW1lcmljKDIxKQpLT3MgPC0gbGlzdCgpCktPc190ZW1wIDwtIG51bWVyaWMobm9fcmVwZXRpdGlvbikKc3Vydml2ZWRfQVNWcyA8LSBsaXN0KCkKQVNWc19mdWxsIDwtIEFTVl9yaWNobmVzcwpLT3NfZnVsbCA8LSByaWNobmVzc19NRiRNRl9HWzFdCnN1cnZpdmVkX0FTVnMgPC0gbGlzdCgpCnMgPC0gQVNWX3JpY2huZXNzLzIwCiNOaW5lIGRpZmZlcmVudCBzY2VuYXJpb3MsIGluY2x1ZGluZyB0aGUgcmFuZG9tLWV4dGluY3Rpb24gc2NlbmFyaW8KZm9yKGkgaW4gMTo5KSB7CiAgS09zW1tpXV0gPC0gbnVtZXJpYygyMSkKICAKICBwcm9iX3Rlc3QgPC0gcHJvcC50YWJsZShzdXJ2aXZhbF9yYXRlX21vZFssIGldW3ByZXNlbmNlXSkgCiAgCiAgI1ByZXBhcmluZyBzdXJ2aXZhbCBzZXF1ZW5jZXMKICBmb3IoaiBpbiAxOm5vX3JlcGV0aXRpb24pIHsKICAgICNmdWxseSBzaHVmZmxpbmcgZm9yIHRoZSBvcmRlciBvZiBzdXJ2aXZhbCAodGhlIGludmVyc2Ugb3JkZXIgb2YgZXh0aW5jdGlvbikKICAgIHN1cnZpdmVkX0FTVnNbW2pdXSA8LSBzYW1wbGUoMTpBU1ZfcmljaG5lc3MsIHNpemUgPSBBU1ZfcmljaG5lc3MsIHJlcGxhY2UgPSBGQUxTRSwgcHJvYiA9IHByb2JfdGVzdCkKICAgICNzdXJ2aXZlZF9BU1ZzW1tqXV0gPC0gc2FtcGxlKDE6bGVuZ3RoKHByZXNlbmNlKSwgc2l6ZSA9IGxlbmd0aChwcmVzZW5jZSksIHJlcGxhY2UgPSBGQUxTRSkKICB9CiAgCiAgI0ZvciBwbG90dGluZyB3aXRoIGF2ZXJhZ2luZyBLT3MgYXQgZWFjaCBzdXJ2aXZhbCBsZXZlbAogICNUaGUgY2FzZSB3aXRoIGEgc2luZ2xlIEFTVgogIEFTVnNbMV0gPC0gMQogIGZvcihqIGluIDE6bm9fcmVwZXRpdGlvbikgewogICAgS09fbGlzdF9zdXJ2aXZlZCA8LSBLT19jb21fYmluYXJpemVkW3N1cnZpdmVkX0FTVnNbW2pdXVsxXSwgXQogICAgS09zX3RlbXBbal0gPC0gc3VtKEtPX2xpc3Rfc3Vydml2ZWQgPiAwKQogIH0KICBLT3NbW2ldXVsxXSA8LSBtZWFuKEtPc190ZW1wKQogIGZvcihrIGluIDI6MjApIHsKICAgIHN1cnZpdmVkX3JpY2huZXNzIDwtIHJvdW5kKHMqKGsgLSAxKSkKICAgIEFTVnNba10gPC0gc3Vydml2ZWRfcmljaG5lc3MKICAgIGZvcihqIGluIDE6bm9fcmVwZXRpdGlvbikgewogICAgICBLT19zdXJ2aXZlZCA8LSBLT19jb21fYmluYXJpemVkW3ByZXNlbmNlW3N1cnZpdmVkX0FTVnNbW2pdXVsxOnN1cnZpdmVkX3JpY2huZXNzXV0sIF0KICAgICAgS09fbGlzdF9zdXJ2aXZlZCA8LSBhcHBseShLT19zdXJ2aXZlZCwgMiwgc3VtKQogICAgICBLT3NfdGVtcFtqXSA8LSBzdW0oS09fbGlzdF9zdXJ2aXZlZCA+IDApICAgIAogICAgfQogICAgS09zW1tpXV1ba10gPC0gbWVhbihLT3NfdGVtcCkKICB9CiAgCiAgayA8LSAyMQogIEFTVnNba10gPC0gQVNWc19mdWxsCiAgS09zW1tpXV1ba10gPC0gS09zX2Z1bGwKICAKICBjb2xvcl9zcGVjaWZpYyA8LSBjKCJibGFjayIsICJkYXJrZ29sZGVucm9kMSIsImNvcmFsMSIsImhvdHBpbmszIiwgImJyb3duNCIsICJsaWdodHNsYXRlZ3JheSIsICJkZWVwc2t5Ymx1ZSIsICJyb3lhbGJsdWU0IiwgInNlYWdyZWVuMyIpCiAgCiAgCiAgaWYoaSA9PSAxKSB7CiAgICBwbG90KEtPc1tbaV1dWzI6MjFdIH4gQVNWc1syOjIxXSAsIHR5cGUgPSAiYiIsIHhsaW0gPSBjKEFTVnNbMl0sIEFTVnNbMjFdKSwgeWxpbSA9IGMoMzAwMCwgS09zW1tpXV1bMjFdKSwgY2V4ID0gMiwgY29sID0gY29sb3Jfc3BlY2lmaWNbaV0sIG1haW4gPSAiQWxsIHNjZW5hcmlvcyBmb3IgQml3YTA3MDMiLCB4bGFiID0gIkFTViByaWNobmVzcyIsIHlsYWIgPSAiS08gcmljaG5lc3MiKSAgCiAgfSBlbHNlIHsKICAgIHBhcihuZXcgPSBUKQogICAgcGxvdChLT3NbW2ldXVsyOjIxXSB+IEFTVnNbMjoyMV0gLCB0eXBlID0gImIiLCB4bGltID0gYyhBU1ZzWzJdLCBBU1ZzWzIxXSksIHlsaW0gPSBjKDMwMDAsIEtPc1tbaV1dWzIxXSksIGNleCA9IDIsIGNvbCA9IGNvbG9yX3NwZWNpZmljW2ldLCBwY2ggPSBpLCBtYWluID0gIiIsIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQogIH0KICBsYWJlbHMgPC0gY29sbmFtZXMoc3Vydml2YWxfcmF0ZV9tb2QpCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCBsZWdlbmQgPSBsYWJlbHMsIGNvbCA9IGNvbG9yX3NwZWNpZmljLCBwY2ggPSAxOjkpCiAgCn0KCmZvcihpIGluIDE6OSl7CiAgaWYoaSA9PSAxKSB7CiAgICBwbG90KGxvZzEwKEtPc1tbaV1dWzI6MjFdKSB+IGxvZzEwKEFTVnNbMjoyMV0pLCB0eXBlID0gImIiLCB4bGltID0gYyhsb2cxMChBU1ZzWzJdKSwgbG9nMTAoQVNWc1syMV0pKSwgeWxpbSA9IGMobG9nMTAoMzAwMCksIGxvZzEwKEtPc1tbaV1dWzIxXSkpLCBjZXggPSAyLCBjb2wgPSBjb2xvcl9zcGVjaWZpY1tpXSwgbWFpbiA9ICJBbGwgc2NlbmFyaW9zIGZvciBCaXdhMDcwMyIsIHhsYWIgPSAiQVNWIHJpY2huZXNzIiwgeWxhYiA9ICJLTyByaWNobmVzcyIpICAKICB9IGVsc2UgewogICAgcGFyKG5ldyA9IFQpCiAgICBwbG90KGxvZzEwKEtPc1tbaV1dWzI6MjFdKSB+IGxvZzEwKEFTVnNbMjoyMV0pLCB0eXBlID0gImIiLCB4bGltID0gYyhsb2cxMChBU1ZzWzJdKSwgbG9nMTAoQVNWc1syMV0pKSwgeWxpbSA9IGMobG9nMTAoMzAwMCksIGxvZzEwKEtPc1tbaV1dWzIxXSkpLCBjZXggPSAyLCBjb2wgPSBjb2xvcl9zcGVjaWZpY1tpXSwgcGNoID0gaSwgbWFpbiA9ICIiLCB4bGFiID0gIiIsIHlsYWIgPSAiIikKICB9CiAgbGFiZWxzIDwtIGNvbG5hbWVzKHN1cnZpdmFsX3JhdGVfbW9kKQogIGxlZ2VuZCgiYm90dG9tcmlnaHQiLCBsZWdlbmQgPSBsYWJlbHMsIGNvbCA9IGNvbG9yX3NwZWNpZmljLCBwY2ggPSAxOjkpCn0KCnBkZigiZmlndXJlMDNhLnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDcsIG9uZWZpbGUgPSBGQUxTRSkKZm9yKGkgaW4gMTo5KXsKICBpZihpID09IDEpIHsKICAgIHBsb3QoS09zW1tpXV1bMjoyMV0gfiBBU1ZzWzI6MjFdICwgdHlwZSA9ICJiIiwgeGxpbSA9IGMoQVNWc1syXSwgQVNWc1syMV0pLCB5bGltID0gYygzMDAwLCBLT3NbW2ldXVsyMV0pLCBjZXggPSAyLCBjb2wgPSBjb2xvcl9zcGVjaWZpY1tpXSwgbWFpbiA9ICJBbGwgc2NlbmFyaW9zIGZvciBCaXdhMDcwMyIsIHhsYWIgPSAiQVNWIHJpY2huZXNzIiwgeWxhYiA9ICJLTyByaWNobmVzcyIpICAKICB9IGVsc2UgewogICAgcGFyKG5ldyA9IFQpCiAgICBwbG90KEtPc1tbaV1dWzI6MjFdIH4gQVNWc1syOjIxXSAsIHR5cGUgPSAiYiIsIHhsaW0gPSBjKEFTVnNbMl0sIEFTVnNbMjFdKSwgeWxpbSA9IGMoMzAwMCwgS09zW1tpXV1bMjFdKSwgY2V4ID0gMiwgY29sID0gY29sb3Jfc3BlY2lmaWNbaV0sIHBjaCA9IGksIG1haW4gPSAiIiwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCiAgfQp9CmxhYmVscyA8LSBjb2xuYW1lcyhzdXJ2aXZhbF9yYXRlX21vZCkKbGVnZW5kKCJib3R0b21yaWdodCIsIGxlZ2VuZCA9IGxhYmVscywgY29sID0gY29sb3Jfc3BlY2lmaWMsIHBjaCA9IDE6OSkKZGV2Lm9mZigpCgpgYGAKCkF0IGVhY2ggbGV2ZWwgb2YgQVNWIHJpY2huZXNzLCBjYWxjdWxhdGluZyB0aGUgYXZlcmFnZXMgZnJvbSByZXBldGl0aW9uIGZpcnN0IGFuZCBtYWtlIGEgc2luZ2xlIGxpbmUgd2l0aCBhdmVyYWdlcwpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQojZm9yIHNhbXBsZV8wNQpwcmVzZW5jZSA8LSB3aGljaChzdGFuZF9BU1ZfY29tX2JpbmFyaXplZCRTMDUgPiAwKQojQVNWIHdpdGggZ3JlYXRlciByaWNobmVzcyBvZiBLT3MgKGxvbmdlciBnZW5vbWVzKSBoYXMgYSBoaWdoZXIgc3Vydml2YWwgcHJvYmFiaWxpdHkKCkFTVl9yaWNobmVzcyA8LSBsZW5ndGgocHJlc2VuY2UpCm5vX3JlcGV0aXRpb24gPC0gMTAwCkFTVnMgPC0gbnVtZXJpYygyMSkKS09zIDwtIGxpc3QoKQpLT3NfdGVtcCA8LSBudW1lcmljKG5vX3JlcGV0aXRpb24pCnN1cnZpdmVkX0FTVnMgPC0gbGlzdCgpCkFTVnNfZnVsbCA8LSBBU1ZfcmljaG5lc3MKS09zX2Z1bGwgPC0gcmljaG5lc3NfTUYkTUZfR1s1XQpzdXJ2aXZlZF9BU1ZzIDwtIGxpc3QoKQpzIDwtIEFTVl9yaWNobmVzcy8yMAojTmluZSBkaWZmZXJlbnQgc2NlbmFyaW9zLCBpbmNsdWRpbmcgdGhlIHJhbmRvbS1leHRpbmN0aW9uIHNjZW5hcmlvCmZvcihpIGluIDE6OSkgewogIEtPc1tbaV1dIDwtIG51bWVyaWMoMjEpCiAgCiAgcHJvYl90ZXN0IDwtIHByb3AudGFibGUoc3Vydml2YWxfcmF0ZV9tb2RbLCBpXVtwcmVzZW5jZV0pIAogIAogICNQcmVwYXJpbmcgc3Vydml2YWwgc2VxdWVuY2VzCiAgZm9yKGogaW4gMTpub19yZXBldGl0aW9uKSB7CiAgICAjZnVsbHkgc2h1ZmZsaW5nIGZvciB0aGUgb3JkZXIgb2Ygc3Vydml2YWwgKHRoZSBpbnZlcnNlIG9yZGVyIG9mIGV4dGluY3Rpb24pCiAgICBzdXJ2aXZlZF9BU1ZzW1tqXV0gPC0gc2FtcGxlKDE6QVNWX3JpY2huZXNzLCBzaXplID0gQVNWX3JpY2huZXNzLCByZXBsYWNlID0gRkFMU0UsIHByb2IgPSBwcm9iX3Rlc3QpCiAgICAjc3Vydml2ZWRfQVNWc1tbal1dIDwtIHNhbXBsZSgxOmxlbmd0aChwcmVzZW5jZSksIHNpemUgPSBsZW5ndGgocHJlc2VuY2UpLCByZXBsYWNlID0gRkFMU0UpCiAgfQogIAogICNGb3IgcGxvdHRpbmcgd2l0aCBhdmVyYWdpbmcgS09zIGF0IGVhY2ggc3Vydml2YWwgbGV2ZWwKICAjVGhlIGNhc2Ugd2l0aCBhIHNpbmdsZSBBU1YKICBBU1ZzWzFdIDwtIDEKICBmb3IoaiBpbiAxOm5vX3JlcGV0aXRpb24pIHsKICAgIEtPX2xpc3Rfc3Vydml2ZWQgPC0gS09fY29tX2JpbmFyaXplZFtzdXJ2aXZlZF9BU1ZzW1tqXV1bMV0sIF0KICAgIEtPc190ZW1wW2pdIDwtIHN1bShLT19saXN0X3N1cnZpdmVkID4gMCkKICB9CiAgS09zW1tpXV1bMV0gPC0gbWVhbihLT3NfdGVtcCkKICBmb3IoayBpbiAyOjIwKSB7CiAgICBzdXJ2aXZlZF9yaWNobmVzcyA8LSByb3VuZChzKihrIC0gMSkpCiAgICBBU1ZzW2tdIDwtIHN1cnZpdmVkX3JpY2huZXNzCiAgICBmb3IoaiBpbiAxOm5vX3JlcGV0aXRpb24pIHsKICAgICAgS09fc3Vydml2ZWQgPC0gS09fY29tX2JpbmFyaXplZFtwcmVzZW5jZVtzdXJ2aXZlZF9BU1ZzW1tqXV1bMTpzdXJ2aXZlZF9yaWNobmVzc11dLCBdCiAgICAgIEtPX2xpc3Rfc3Vydml2ZWQgPC0gYXBwbHkoS09fc3Vydml2ZWQsIDIsIHN1bSkKICAgICAgS09zX3RlbXBbal0gPC0gc3VtKEtPX2xpc3Rfc3Vydml2ZWQgPiAwKSAgICAKICAgIH0KICAgIEtPc1tbaV1dW2tdIDwtIG1lYW4oS09zX3RlbXApCiAgfQogIAogIGsgPC0gMjEKICBBU1ZzW2tdIDwtIEFTVnNfZnVsbAogIEtPc1tbaV1dW2tdIDwtIEtPc19mdWxsCiAgCiAgaWYoaSA9PSAxKSB7CiAgICBwbG90KEtPc1tbaV1dWzI6MjFdIH4gQVNWc1syOjIxXSAsIHR5cGUgPSAiYiIsIHhsaW0gPSBjKEFTVnNbMl0sIEFTVnNbMjFdKSwgeWxpbSA9IGMoMzAwMCwgS09zW1tpXV1bMjFdKSwgY2V4ID0gMiwgY29sID0gY29sb3Jfc3BlY2lmaWNbaV0sIG1haW4gPSAiQWxsIHNjZW5hcmlvcyBmb3IgWWFzdTA3MDkiLCB4bGFiID0gIkFTViByaWNobmVzcyIsIHlsYWIgPSAiS08gcmljaG5lc3MiKSAgCiAgfSBlbHNlIHsKICAgIHBhcihuZXcgPSBUKQogICAgcGxvdChLT3NbW2ldXVsyOjIxXSB+IEFTVnNbMjoyMV0gLCB0eXBlID0gImIiLCB4bGltID0gYyhBU1ZzWzJdLCBBU1ZzWzIxXSksIHlsaW0gPSBjKDMwMDAsIEtPc1tbaV1dWzIxXSksIGNleCA9IDIsIGNvbCA9IGNvbG9yX3NwZWNpZmljW2ldLCBwY2ggPSBpLCBtYWluID0gIiIsIHhsYWIgPSAiIiwgeWxhYiA9ICIiKQogIH0KICBsYWJlbHMgPC0gY29sbmFtZXMoc3Vydml2YWxfcmF0ZV9tb2QpCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCBsZWdlbmQgPSBsYWJlbHMsIGNvbCA9IGNvbG9yX3NwZWNpZmljLCBwY2ggPSAxOjkpCiAgCn0KCmZvcihpIGluIDE6OSl7CiAgaWYoaSA9PSAxKSB7CiAgICBwbG90KGxvZzEwKEtPc1tbaV1dWzI6MjFdKSB+IGxvZzEwKEFTVnNbMjoyMV0pLCB0eXBlID0gImIiLCB4bGltID0gYyhsb2cxMChBU1ZzWzJdKSwgbG9nMTAoQVNWc1syMV0pKSwgeWxpbSA9IGMobG9nMTAoMzAwMCksIGxvZzEwKEtPc1tbaV1dWzIxXSkpLCBjZXggPSAyLCBjb2wgPSBjb2xvcl9zcGVjaWZpY1tpXSwgbWFpbiA9ICJBbGwgc2NlbmFyaW9zIGZvciBZYXN1MDcwOSIsIHhsYWIgPSAiQVNWIHJpY2huZXNzIiwgeWxhYiA9ICJLTyByaWNobmVzcyIpICAKICB9IGVsc2UgewogICAgcGFyKG5ldyA9IFQpCiAgICBwbG90KGxvZzEwKEtPc1tbaV1dWzI6MjFdKSB+IGxvZzEwKEFTVnNbMjoyMV0pLCB0eXBlID0gImIiLCB4bGltID0gYyhsb2cxMChBU1ZzWzJdKSwgbG9nMTAoQVNWc1syMV0pKSwgeWxpbSA9IGMobG9nMTAoMzAwMCksIGxvZzEwKEtPc1tbaV1dWzIxXSkpLCBjZXggPSAyLCBjb2wgPSBjb2xvcl9zcGVjaWZpY1tpXSwgcGNoID0gaSwgbWFpbiA9ICIiLCB4bGFiID0gIiIsIHlsYWIgPSAiIikKICB9CiAgbGFiZWxzIDwtIGNvbG5hbWVzKHN1cnZpdmFsX3JhdGVfbW9kKQogIGxlZ2VuZCgiYm90dG9tcmlnaHQiLCBsZWdlbmQgPSBsYWJlbHMsIGNvbCA9IGNvbG9yX3NwZWNpZmljLCBwY2ggPSAxOjkpCn0KCnBkZigiZmlndXJlMDNiLnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDcsIG9uZWZpbGUgPSBGQUxTRSkKZm9yKGkgaW4gMTo5KXsKICBpZihpID09IDEpIHsKICAgIHBsb3QoS09zW1tpXV1bMjoyMV0gfiBBU1ZzWzI6MjFdICwgdHlwZSA9ICJiIiwgeGxpbSA9IGMoQVNWc1syXSwgQVNWc1syMV0pLCB5bGltID0gYygzMDAwLCBLT3NbW2ldXVsyMV0pLCBjZXggPSAyLCBjb2wgPSBjb2xvcl9zcGVjaWZpY1tpXSwgbWFpbiA9ICJBbGwgc2NlbmFyaW9zIGZvciBZYXN1MDcwOSIsIHhsYWIgPSAiQVNWIHJpY2huZXNzIiwgeWxhYiA9ICJLTyByaWNobmVzcyIpICAKICB9IGVsc2UgewogICAgcGFyKG5ldyA9IFQpCiAgICBwbG90KEtPc1tbaV1dWzI6MjFdIH4gQVNWc1syOjIxXSAsIHR5cGUgPSAiYiIsIHhsaW0gPSBjKEFTVnNbMl0sIEFTVnNbMjFdKSwgeWxpbSA9IGMoMzAwMCwgS09zW1tpXV1bMjFdKSwgY2V4ID0gMiwgY29sID0gY29sb3Jfc3BlY2lmaWNbaV0sIHBjaCA9IGksIG1haW4gPSAiIiwgeGxhYiA9ICIiLCB5bGFiID0gIiIpCiAgfQp9CmxhYmVscyA8LSBjb2xuYW1lcyhzdXJ2aXZhbF9yYXRlX21vZCkKbGVnZW5kKCJib3R0b21yaWdodCIsIGxlZ2VuZCA9IGxhYmVscywgY29sID0gY29sb3Jfc3BlY2lmaWMsIHBjaCA9IDE6OSkKZGV2Lm9mZigpCgpgYGAKIyMjIyBbNS4yLjRdIERlZmluaXRpb24gb2YgZnVuY3Rpb25zIGZvciBhIGdpdmVuIGV4dGluY3Rpb24gc2VxdWVuY2UKYGBge3J9CnNhbXBsZV9JRCA8LSBjKDEsIDIsIDMsIDQsIDUsIDYsIDcsIDgsIDExLCAxNywgMTgsIDE5LCAyMCkgI29ubHkgYSBwYXJ0IG9mIHNhbXBsZXMgaXMgdXNlZAojIyNsaXN0IG9mIHBhcmFtZXRlcnMjIyMKI2NvbV9iaW5hcml6ZWQ6IEFTViBjb21wb3NpdGlvbiBkYXRhZnJhbWUgYmluYXJpemVkCiNLT19iaW5hcml6ZWQ6IEtPIGNvbXBvc2l0aW9uIGRhdGFmcmFtZSBiaW5hcml6ZWQKI3N1cnZfcHJvYjogZXh0aW5jdGlvbiBzZXF1ZW5jZXMgKHdpdGggcmVwbGljYXRpb25zKSBhcyBhIGxpc3QKc2ltX2V4dGluY3Rpb24gPC0gZnVuY3Rpb24oY29tX2JpbmFyaXplZCwgS09fYmluYXJpemVkLCBzdXJ2X3Byb2IgPSBOVUxMLCByZXBldGl0aW9uLCB0aXRsZSA9ICJyYW5kb20iLCBncmFwaGljID0gVFJVRSkgewogIHByZXNlbmNlIDwtIG51bWVyaWMobGVuZ3RoKHNhbXBsZV9JRCkpCiAgQVNWc19mdWxsIDwtIG51bWVyaWMobGVuZ3RoKHNhbXBsZV9JRCkpCiAgS09zX2Z1bGwgPC0gbnVtZXJpYyhsZW5ndGgoc2FtcGxlX0lEKSkKICBzbG9wZSA8LSBudW1lcmljKGxlbmd0aChzYW1wbGVfSUQpKQogIHNsb3BlX3VwIDwtIG51bWVyaWMobGVuZ3RoKHNhbXBsZV9JRCkpCiAgc2xvcGVfZG93biA8LSBudW1lcmljKGxlbmd0aChzYW1wbGVfSUQpKQogIHIyX2FkanVzdGVkIDwtIG51bWVyaWMobGVuZ3RoKHNhbXBsZV9JRCkpCiAgCiAgI2ZvcihzYW1wbGVfbm8gaW4gMToyKXsKICBmb3Ioc2FtcGxlX25vIGluIDE6bGVuZ3RoKGNvbV9iaW5hcml6ZWRbMSxdKSl7CiAgICBwcmVzZW5jZSA8LSB3aGljaChjb21fYmluYXJpemVkWywgc2FtcGxlX25vXSA+IDApCiAgICBBU1ZfcmljaG5lc3MgPC0gbGVuZ3RoKHByZXNlbmNlKQogICAgQVNWcyA8LSBudW1lcmljKDIxKQogICAgS09zIDwtIG51bWVyaWMoMjEpCiAgICBLT3NfdGVtcCA8LSBudW1lcmljKHJlcGV0aXRpb24pCiAgICBzdXJ2aXZlZF9BU1ZzIDwtIGxpc3QoKQogICAgQVNWc19mdWxsW3NhbXBsZV9ub10gPC0gQVNWX3JpY2huZXNzCiAgICBLT3NfZnVsbFtzYW1wbGVfbm9dIDwtIHN1bSh0KEtPX2JpbmFyaXplZCkgJSolIGNvbV9iaW5hcml6ZWRbLCBzYW1wbGVfbm9dID4gMCkKICAgIHMgPC0gQVNWX3JpY2huZXNzLzIwCiAgICAKICAgICNSZWZyZXNoIHRoZSBncmFwaGljcyBmb3IgZWFjaCBzYW1wbGVfbm8KICAgIHBhcihuZXcgPSBGKQogICAgCiAgICAjU2V0dGluZyBzdXJ2aXZhbCBwcm9iYWJpbGl0eQogICAgaWYoaXMubnVsbChzdXJ2X3Byb2IpKSB7CiAgICAgIHN1cnZpdmFsX3Byb2IgPC0gTlVMTAogICAgfSBlbHNlIHsKICAgICAgc3Vydml2YWxfcHJvYiA8LSBzdXJ2X3Byb2JbcHJlc2VuY2VdCiAgICB9CiAgICAKICAgICNQcmVwYXJpbmcgc3Vydml2YWwgc2VxdWVuY2VzCiAgICBmb3IoaiBpbiAxOnJlcGV0aXRpb24pIHsKICAgICAgI2Z1bGx5IHNodWZmbGluZyBmb3IgdGhlIG9yZGVyIG9mIGFwcGVhcmFuY2UgKHRoZSBpbnZlcnNlIG9yZGVyIG9mIGV4dGluY3Rpb24pCiAgICAgIHN1cnZpdmVkX0FTVnNbW2pdXSA8LSBzYW1wbGUoMTpsZW5ndGgocHJlc2VuY2UpLCBzaXplID0gbGVuZ3RoKHByZXNlbmNlKSwgcmVwbGFjZSA9IEZBTFNFLCBwcm9iID0gc3Vydml2YWxfcHJvYikKICAgIH0KICAgICNGb3IgcGxvdHRpbmcgZWFjaCBleHRpbmN0aW9uIHNlcXVlbmNlCiAgICBmb3IoaiBpbiAxOnJlcGV0aXRpb24pIHsKICAgICAgI1RoZSBjYXNlIHdpdGggYSBzaW5nbGUgQVNWCiAgICAgICNBU1ZzWzFdIDwtIDEKICAgICAgI0tPX2xpc3Rfc3Vydml2ZWQgPC0gS09fYmluYXJpemVkW3N1cnZpdmVkX0FTVnNbW2pdXVsxXSwgXQogICAgICAjS09zWzFdIDwtIHN1bShLT19saXN0X3N1cnZpdmVkID4gMCkKICAgICAgZm9yKGsgaW4gMzoyMCkgewogICAgICAgIHN1cnZpdmVkX3JpY2huZXNzIDwtIHJvdW5kKHMqKGsgLSAxKSkKICAgICAgICBBU1ZzW2tdIDwtIHN1cnZpdmVkX3JpY2huZXNzCiAgICAgICAgS09fc3Vydml2ZWQgPC0gS09fYmluYXJpemVkW3ByZXNlbmNlW3N1cnZpdmVkX0FTVnNbW2pdXVsxOnN1cnZpdmVkX3JpY2huZXNzXV0sIF0KICAgICAgICBLT19saXN0X3N1cnZpdmVkIDwtIGFwcGx5KEtPX3N1cnZpdmVkLCAyLCBzdW0pCiAgICAgICAgS09zW2tdIDwtIHN1bShLT19saXN0X3N1cnZpdmVkID4gMCkKICAgICAgfQogICAgICAjVGhlIGNhc2Ugd2l0aCBhbGwgQVNWcwogICAgICBrIDwtIDIxCiAgICAgIEFTVnNba10gPC0gQVNWc19mdWxsW3NhbXBsZV9ub10KICAgICAgS09zW2tdIDwtIEtPc19mdWxsW3NhbXBsZV9ub10KICAKICAgICAgI2ZpdHRlZF9wb3dlciA8LSBsbShmb3JtdWxhID0gbG9nMTAoS09zKSB+IGxvZzEwKEFTVnMpKQogICAgICAjc2xvcGVfZWFjaFtqXSA8LSBmaXR0ZWRfcG93ZXIkY29lZmZpY2llbnRzWzJdCiAgICAgIGlmKGdyYXBoaWMgPT0gVFJVRSkgewogICAgICAgIHBsb3QobG9nMTAoS09zWzM6MjFdKSB+IGxvZzEwKEFTVnNbMzoyMV0pICwgdHlwZSA9ICJsIiwgeGxpbSA9IGMobG9nMTAoQVNWc1szXSksIGxvZzEwKEFTVnNbMjFdKSksIHlsaW0gPSBjKGxvZzEwKDMwMDApLCBsb2cxMChLT3NbMjFdKSksIGNvbCA9IDgpCiAgICAgICAgcGFyKG5ldyA9IFQpCiAgICAgIH0KICAgICAgI3ByaW50KGopCiAgICB9I2VuZCBvZiBmb3IgagogICAgCiAgICAjRm9yIHBsb3R0aW5nIHdpdGggYXZlcmFnaW5nIEtPcyBhdCBlYWNoIHN1cnZpdmFsIGxldmVsCiAgICAjVGhlIGNhc2Ugd2l0aCBhIHNpbmdsZSBBU1YKICAgICNBU1ZzWzFdIDwtIDEKICAgIGZvcihqIGluIDE6cmVwZXRpdGlvbikgewogICAgICBLT19saXN0X3N1cnZpdmVkIDwtIEtPX2JpbmFyaXplZFtzdXJ2aXZlZF9BU1ZzW1tqXV1bMV0sIF0KICAgICAgS09zX3RlbXBbal0gPC0gc3VtKEtPX2xpc3Rfc3Vydml2ZWQgPiAwKQogICAgfQogICAgS09zWzFdIDwtIG1lYW4oS09zX3RlbXApCiAgICBmb3IoayBpbiAzOjIwKSB7CiAgICAgIHN1cnZpdmVkX3JpY2huZXNzIDwtIHJvdW5kKHMqKGsgLSAxKSkKICAgICAgQVNWc1trXSA8LSBzdXJ2aXZlZF9yaWNobmVzcwogICAgICBmb3IoaiBpbiAxOnJlcGV0aXRpb24pIHsKICAgICAgICBLT19zdXJ2aXZlZCA8LSBLT19iaW5hcml6ZWRbcHJlc2VuY2Vbc3Vydml2ZWRfQVNWc1tbal1dWzE6c3Vydml2ZWRfcmljaG5lc3NdXSwgXQogICAgICAgIEtPX2xpc3Rfc3Vydml2ZWQgPC0gYXBwbHkoS09fc3Vydml2ZWQsIDIsIHN1bSkKICAgICAgICBLT3NfdGVtcFtqXSA8LSBzdW0oS09fbGlzdF9zdXJ2aXZlZCA+IDApICAgIAogICAgICB9CiAgICAgIEtPc1trXSA8LSBtZWFuKEtPc190ZW1wKQogICAgfQoKICAgIGsgPC0gMjEKICAgIEFTVnNba10gPC0gQVNWc19mdWxsW1tzYW1wbGVfbm9dXQogICAgS09zW2tdIDwtIEtPc19mdWxsW1tzYW1wbGVfbm9dXQogICAgIzAtOTAlIHJlZHVjdGlvbiB3aXRoIHRoZSBjb2Fyc2UgaW50ZXJ2YWwKICAgIGZpdHRlZF9wb3dlciA8LSBsbShmb3JtdWxhID0gbG9nMTAoS09zWzM6MjFdKSB+IGxvZzEwKEFTVnNbMzoyMV0pKQogICAgc2xvcGVbc2FtcGxlX25vXSA8LSBmaXR0ZWRfcG93ZXIkY29lZmZpY2llbnRzWzJdCiAgICAKICAgIHRpdGxlX3RleHQgPC0gcGFzdGUoc2FtcGxlX2luZm8kRGVzY3JpcHRpb25bc2FtcGxlX0lEW3NhbXBsZV9ub11dLCB0aXRsZSwgc2VwID0gIjoiKQogICAgaWYoZ3JhcGhpYyA9PSBUUlVFKSB7CiAgICAgIHBsb3QobG9nMTAoS09zWzM6MjFdKSB+IGxvZzEwKEFTVnNbMzoyMV0pICwgdHlwZSA9ICJiIiwgeGxpbSA9IGMobG9nMTAoQVNWc1szXSksIGxvZzEwKEFTVnNbMjFdKSksIHlsaW0gPSBjKGxvZzEwKDMwMDApLCBsb2cxMChLT3NbMjFdKSksIGNleCA9IDIsIGNvbCA9IDQsIG1haW4gPSB0aXRsZV90ZXh0KQojcHJpbnQoaikKICAgICAgYWJsaW5lKGZpdHRlZF9wb3dlciwgY29sID0gNSkKICAgIH0KICAgIHNsb3BlX2Rvd25bc2FtcGxlX25vXSA8LSBjb25maW50LmxtKGZpdHRlZF9wb3dlcilbMiwgMV0KICAgIHNsb3BlX3VwW3NhbXBsZV9ub10gPC0gY29uZmludC5sbShmaXR0ZWRfcG93ZXIpWzIsIDJdCiAgICByMl9hZGp1c3RlZFtzYW1wbGVfbm9dIDwtIHN1bW1hcnkoZml0dGVkX3Bvd2VyKSRhZGouci5zcXVhcmVkCgogIH0jZW5kIG9mIGZvciBzYW1wbGVfbm8KICBzdW1tYXJ5X2V4dGluY3Rpb24gPC0gZGF0YS5mcmFtZShzYW1wbGUgPSBzYW1wbGVfaW5mbyREZXNjcmlwdGlvbltzYW1wbGVfSURdLCBBU1ZzX2Z1bGwsIEtPc19mdWxsLCBzbG9wZSwgc2xvcGVfZG93biwgc2xvcGVfdXAsIHIyX2FkanVzdGVkKQogIAogIHJldHVybihzdW1tYXJ5X2V4dGluY3Rpb24pCn0KYGBgCgojIyMjIFs1LjIuNV0gUGFyYWxsZWwgY2FsY3VsYXRpb24gZm9yIG5vbi1yYW5kb24gZXh0aW5jdGlvbnMgdy9vIGdyYXBoaWNzCmBgYHtyfQojc2V0LnNlZWQoMTIzNDU2NykKbm9ucmFuZG9tX3NpbSA8LSBsaXN0KCkKCmxhYmVscyA8LSBjb2xuYW1lcyhzdXJ2aXZhbF9yYXRlX21vZCkKCm5vbnJhbmRvbV9zaW0gPC0gbWNsYXBwbHkoMTo5LCBmdW5jdGlvbihpKSB7CiAgcmVzdWx0X3NpbSA8LSBzaW1fZXh0aW5jdGlvbihzdGFuZF9BU1ZfY29tX2JpbmFyaXplZCwgS09fY29tX2JpbmFyaXplZCwgc3Vydl9wcm9iID0gc3Vydml2YWxfcmF0ZV9tb2RbLCBpXSwgcmVwZXRpdGlvbiA9IDEwMCwgdGl0bGUgPSBsYWJlbHNbaV0sIGdyYXBoaWMgPSBGQUxTRSkKICByZXN1bHRfc2ltCn0sIG1jLmNvcmVzID0gOSkKCmBgYAoKUmVzdWx0cwpgYGB7cn0Kbm9ucmFuZG9tX3NpbQpgYGAKCiMjIyMgWzUuMi42XSBTdW1tYXJ5ClByZXBhcmluZyBhIGRhdGFmcmFtZSBmb3IgZ3JhcGhpYyBwcmVzZW50YXRpb24KYGBge3J9CnNsb3BlX3IgPC0gbGlzdCgpCmZvcihqIGluIDE6OSkgewogIHNsb3BlX3JbW2pdXSA8LSBub25yYW5kb21fc2ltW1tqXV0kc2xvcGUKfQpzbG9wZV9zdW1tYXJ5IDwtIE5VTEwKZm9yKGogaW4gMTo5KSB7CiAgc2xvcGVfc3VtbWFyeSA8LSBhcHBlbmQoc2xvcGVfc3VtbWFyeSwgc2xvcGVfcltbal1dKQp9Cmxlbmd0aChzbG9wZV9zdW1tYXJ5KQpzYW1wbGVfaWQgPC0gcmVwKG5vbnJhbmRvbV9zaW1bWzFdXSRzYW1wbGUsIDkpCnNpdGVzIDwtIHJlcChjKCJiaXdhIiwgImFuZSIsICJlY2hpIiwgImhpbm8iLCAieWFzdSIsICJiaXdhIiwgImFuZSIsICJlY2hpIiwgImJpd2EiLCAiYW5lIiwgImVjaGkiLCAiaGlubyIsICJ5YXN1IiksIDkpCmRhdGVzIDwtIHJlcChjKCIyMDE5MDcwMyIsICIyMDE5MDcwOSIsICIyMDE5MDcwOSIsICIyMDE5MDcwOSIsICIyMDE5MDcwOSIsICIyMDE5MDczMCIsICIyMDE5MDgwNyIsICIyMDE5MDgwNyIsICIyMDE5MDkxMCIsICIyMDE5MTAxNSIsICIyMDE5MTAxNSIsICIyMDE5MTAxNSIsICIyMDE5MTAxNSIpLCA5KQp4dHlwZSA8LSBjKHJlcCgicmFuZG9tIiwgMTMpLCByZXAoIkYxIiwgMTMpLCByZXAoIkYyIiwgMTMpLCByZXAoIkYzIiwgMTMpLCByZXAoIkY0IiwgMTMpLCByZXAoIkExIiwgMTMpLCByZXAoIkEyIiwgMTMpLCByZXAoIkEzIiwgMTMpLCByZXAoIkE0IiwgMTMpKQp4dHlwZV9uIDwtIGMocmVwKDEsIDEzKSwgcmVwKDIsIDEzKSwgcmVwKDMsIDEzKSwgcmVwKDQsIDEzKSwgcmVwKDUsIDEzKSwgcmVwKDYsIDEzKSwgcmVwKDcsIDEzKSwgcmVwKDgsIDEzKSwgcmVwKDksIDEzKSkKc2xvcGVfMiA8LSBzbG9wZV9zdW1tYXJ5IC0gcmVwKHNsb3BlX3N1bW1hcnlbMToxM10sIDkpICNub3JtYWxpemVkIGJ5IHJhbmRvbSBzY2VuYXJpbyB0aHJvdWdoIHN1YnN0cmFjdGlvbgpzbG9wZV8zIDwtIHNsb3BlX3N1bW1hcnkvcmVwKHNsb3BlX3N1bW1hcnlbMToxM10sIDkpICNub3JtYWxpemVkIGJ5IHJhbmRvbSBzY2VuYXJpbyB0aHJvdWdoIGRpdmlzaW9uCiAgCnNsb3BlX3N1bW1hcnkyIDwtIGRhdGEuZnJhbWUoZGF0ZXMsIHNpdGVzLCB4dHlwZSwgeHR5cGVfbiwgc2xvcGUgPSBzbG9wZV9zdW1tYXJ5LCBzbG9wZV9ucyA9IHNsb3BlXzIsIHNsb3BlX25kIDwtIHNsb3BlXzMpCnNsb3BlX3N1bW1hcnkyJHh0eXBlMiA8LSBmYWN0b3Ioc2xvcGVfc3VtbWFyeTIkeHR5cGUsIGxldmVscz1jKCJyYW5kb20iLCAiRjEiLCAiRjIiLCAiRjMiLCAiRjQiLCAiQTEiLCAiQTIiLCAiQTMiLCAiQTQiKSkKYGBgCkZpZ3VyZSA0CmBgYHtyfQpjdXN0b21fbGFiZWxzIDwtIGMoInJhbmRvbSIsICJGMSIsICJGMiIsICJGMyIsICJGNCIsICJBMSIsICJBMiIsICJBMyIsICJBNCIpCmZpZzRfbm8xIDwtIGdncGxvdChkYXRhID0gc2xvcGVfc3VtbWFyeTIpICsK44CAZ2VvbV9saW5lKGFlcyh4ID0geHR5cGVfbiwgeSA9IHNsb3BlLCBncm91cCA9IHNhbXBsZV9pZCwgY29sb3IgPSBkYXRlcykpICsKICBnZW9tX3BvaW50KGFlcyh4ID0geHR5cGVfbiwgeSA9IHNsb3BlLCBjb2xvciA9IGRhdGVzLCBzaGFwZSA9IHNpdGVzKSwgc2l6ZSA9IDMpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjkpLCBsYWJlbHMgPSBjdXN0b21fbGFiZWxzKSArIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDE1LCAxNiwgMTcsIDUsIDYpKSArIHRoZW1lX2J3KCkgKyAgIAogIGxhYnMgKHRpdGxlID0gIkRpcmVjdCBjb21wYXJpc29uIG9mIGV4cG9uZW50cyIsIHggPSAiZXh0aW5jdGlvbiBzY2VuYXJpb3MiLCB5ID0gInJlZHVuZGFuY3kgZXhwb25lbnQgKGEpIikgCgpmaWc0X25vMiA8LSBnZ3Bsb3QoZGF0YSA9IHNsb3BlX3N1bW1hcnkyKSArCuOAgGdlb21fbGluZShhZXMoeCA9IHh0eXBlX24sIHkgPSBzbG9wZV9ucywgZ3JvdXAgPSBzYW1wbGVfaWQsIGNvbG9yID0gZGF0ZXMpKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHh0eXBlX24sIHkgPSBzbG9wZV9ucywgY29sb3IgPSBkYXRlcywgc2hhcGUgPSBzaXRlcyksIHNpemUgPSAzKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoMTo5KSwgbGFiZWxzID0gY3VzdG9tX2xhYmVscykgKyBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxNSwgMTYsIDE3LCA1LCA2KSkgKyB0aGVtZV9idygpICsgICAgCiAgbGFicyAodGl0bGUgPSAiQ29tcGFyaXNvbiB0aHJvdWdoIHN1YnN0cmFjdGluZyByYW5kb20gc2NlbmFyaW8gb2YgZXhwb25lbnRzIiwgeCA9ICJleHRpbmN0aW9uIHNjZW5hcmlvcyIsIHkgPSAicmVkdW5kYW5jeSBleHBvbmVudCAoYSkiKSAKCmZpZzRfbm8zIDwtIGdncGxvdChkYXRhID0gc2xvcGVfc3VtbWFyeTIpICsK44CAZ2VvbV9saW5lKGFlcyh4ID0geHR5cGVfbiwgeSA9IHNsb3BlX25kLCBncm91cCA9IHNhbXBsZV9pZCwgY29sb3IgPSBkYXRlcykpICsKICBnZW9tX3BvaW50KGFlcyh4ID0geHR5cGVfbiwgeSA9IHNsb3BlX25kLCBjb2xvciA9IGRhdGVzLCBzaGFwZSA9IHNpdGVzKSwgc2l6ZSA9IDMpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjkpLCBsYWJlbHMgPSBjdXN0b21fbGFiZWxzKSArIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDE1LCAxNiwgMTcsIDUsIDYpKSArIHRoZW1lX2J3KCkgKyAgIAogbGFicyAodGl0bGUgPSAiQ29tcGFyaXNvbiB0aHJvdWdoIGRpdmlzaW5nIGJ5IHJhbmRvbSBzY2VuYXJpbyBvZiBleHBvbmVudHMiLCB4ID0gImV4dGluY3Rpb24gc2NlbmFyaW9zIiwgeSA9ICJyZWR1bmRhbmN5IGV4cG9uZW50IChhKSIpIAoKZmlnNF9ubzQgPC0gZ2dwbG90KHNsb3BlX3N1bW1hcnkyLCBhZXMoeHR5cGUyLCBzbG9wZV9ucykpKwogICAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkrCiAgICBnZW9tX2ppdHRlcihhZXMoc2hhcGUgPSBzaXRlcywgY29sb3IgPSBkYXRlcyksd2lkdGggPSAwLjI1LCBzaXplID0gMykrCiAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxNSwgMTYsIDE3LCA1LCA2KSkrCiAgICB0aGVtZV9idygpICsKICAgIGxhYnMgKHRpdGxlID0gIkNvbXBhcmlzb24gdGhyb3VnaCBzdWJzdHJhY3RpbmcgcmFuZG9tIHNjZW5hcmlvIG9mIGV4cG9uZW50cyIsIHggPSAiRXh0aW5jdGlvbiBzY2VuYXJpb3MiLCB5ID0gIlJlZHVuZGFuY3kgZXhwb25lbnQgKGEpIikgCgpwbG90KGZpZzRfbm8xKQpwbG90KGZpZzRfbm8yKQpwbG90KGZpZzRfbm8zKQpwbG90KGZpZzRfbm80KQoKcGRmKCJmaWd1cmUwNGEucGRmIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNywgb25lZmlsZSA9IEZBTFNFKQpwbG90KGZpZzRfbm8xKQojIENsb3NlIHRoZSBQb3N0U2NyaXB0IGRldmljZQpkZXYub2ZmKCkKCnBkZigiZmlndXJlMDRiLnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDcsIG9uZWZpbGUgPSBGQUxTRSkKcGxvdChmaWc0X25vNCkKIyBDbG9zZSB0aGUgUG9zdFNjcmlwdCBkZXZpY2UKZGV2Lm9mZigpCmBgYAoKCgojIyBbNl0gQXNzZW1ibHkgZnJvbSB0aGUgbWV0YWNvbW11bml0eQojIyMgWzYuMV0gRGVmaW5pdGlvbiBvZiBmdW5jdGlvbiBmb3IgYSBnaXZlbiBzY2VuYXJpbyB3aXRoIHRoZSBtZXRhY29tbXVuaXR5CkF0IGVhY2ggbGV2ZWwgb2YgQVNWIHJpY2huZXNzIGZvciBlYWNoIGV4dGluY3Rpb24gc2NlbmFyaW8sIHByZXBhcmluZyAyMDAgcmVwbGljYXRpb25zCmBgYHtyfQpzaW1fZXh0aW5jdGlvbk0gPC0gZnVuY3Rpb24oY29tX2JpbmFyaXplZCwgS09fYmluYXJpemVkLCBzdXJ2X3Byb2IgPSBOVUxMLCBub19yZXBldGl0aW9uLCBzY2VuYXJpbyA9ICJTMSIpIHsKICBBU1ZfcmljaG5lc3NNIDwtIGxlbmd0aChjb21fYmluYXJpemVkWywgMV0pCiAgS09fcmljaG5lc3NNIDwtIHN1bShhcHBseShLT19iaW5hcml6ZWQsIDIsIHN1bSkgPiAwKQogIHByb2JfdGVzdE0gPC0gcHJvcC50YWJsZShzdXJ2X3Byb2IpCiAgQVNWc00gPC0gbnVtZXJpYygyMSkKICBLT3NfdGVtcE0gPC0gbnVtZXJpYyhub19yZXBldGl0aW9uKQogIEtPc185NzUgPC0gbnVtZXJpYygyMSkKICBLT3NfMDI1IDwtIG51bWVyaWMoMjEpCiAgS09zX21lYW4gPC0gbnVtZXJpYygyMSkKICBzdXJ2aXZlZF9BU1ZzTSA8LSBsaXN0KCkKICBzIDwtIEFTVl9yaWNobmVzc00vMjAgIAogIAogICNQcmVwYXJpbmcgc3Vydml2YWwgc2VxdWVuY2VzCiAgZm9yKGogaW4gMTpub19yZXBldGl0aW9uKSB7CiAgICAjZnVsbHkgc2h1ZmZsaW5nIGZvciB0aGUgb3JkZXIgb2Ygc3Vydml2YWwgKHRoZSBpbnZlcnNlIG9yZGVyIG9mIGV4dGluY3Rpb24pCiAgICBzdXJ2aXZlZF9BU1ZzTVtbal1dIDwtIHNhbXBsZSgxOkFTVl9yaWNobmVzc00sIHNpemUgPSBBU1ZfcmljaG5lc3NNLCByZXBsYWNlID0gRkFMU0UsIHByb2IgPSBwcm9iX3Rlc3RNKQogIH0KICAKICBrIDwtIDEKICBBU1ZzTVtrXSA8LSAxMDAKICBmb3IoaiBpbiAxOm5vX3JlcGV0aXRpb24pIHsKICAgIEtPX3N1cnZpdmVkIDwtIEtPX2NvbV9iaW5hcml6ZWRbc3Vydml2ZWRfQVNWc01bW2pdXVsxOkFTVnNNW2tdXSwgXQogICAgS09fbGlzdF9zdXJ2aXZlZCA8LSBhcHBseShLT19zdXJ2aXZlZCwgMiwgc3VtKQogICAgS09zX3RlbXBNW2pdIDwtIHN1bShLT19saXN0X3N1cnZpdmVkID4gMCkKICB9CiAgS09zX21lYW5ba10gPC0gbWVhbihLT3NfdGVtcE0pICAjbWVhbiBvZiB0aGUgcmVwbGljYXRpb25zCiAgS09zXzk3NVtrXSA8LSBxdWFudGlsZShLT3NfdGVtcE0sIHByb2IgPSAwLjk3NSkgI1VwcGVyIGJvdW5kYXJ5IG9mIDk1JSBjb25maWRlbmNlIGludGVydmFsCiAgS09zXzAyNVtrXSA8LSBxdWFudGlsZShLT3NfdGVtcE0sIHByb2IgPSAwLjAyNSkgI0xvd2VyIGJvdW5kYXJ5IG9mIDk1JSBjb25maWRlbmNlIGludGVydmFsCgogIGZvcihrIGluIDI6MjApIHsKICAgIEFTVnNNW2tdIDwtIHJvdW5kKHMqKGsgLSAxKSkKICAgIGZvcihqIGluIDE6bm9fcmVwZXRpdGlvbikgewogICAgICBLT19zdXJ2aXZlZCA8LSBLT19jb21fYmluYXJpemVkW3N1cnZpdmVkX0FTVnNNW1tqXV1bMTpBU1ZzTVtrXV0sIF0KICAgICAgS09fbGlzdF9zdXJ2aXZlZCA8LSBhcHBseShLT19zdXJ2aXZlZCwgMiwgc3VtKQogICAgICBLT3NfdGVtcE1bal0gPC0gc3VtKEtPX2xpc3Rfc3Vydml2ZWQgPiAwKQogICAgfQogICAgS09zX21lYW5ba10gPC0gbWVhbihLT3NfdGVtcE0pICAjbWVhbiBvZiB0aGUgcmVwbGljYXRpb25zCiAgICBLT3NfOTc1W2tdIDwtIHF1YW50aWxlKEtPc190ZW1wTSwgcHJvYiA9IDAuOTc1KSAjVXBwZXIgYm91bmRhcnkgb2YgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICAgIEtPc18wMjVba10gPC0gcXVhbnRpbGUoS09zX3RlbXBNLCBwcm9iID0gMC4wMjUpICNMb3dlciBib3VuZGFyeSBvZiA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbAogIH0KICAjVGhlIGNhc2Ugd2l0aCBhbGwgQVNWcwogIGsgPC0gMjEKICBBU1ZzTVtrXSA8LSBBU1ZfcmljaG5lc3NNCiAgS09zX21lYW5ba10gPC0gS09fcmljaG5lc3NNCiAgS09zXzk3NVtrXSA8LSBLT19yaWNobmVzc00KICBLT3NfMDI1W2tdIDwtIEtPX3JpY2huZXNzTQogIAogIHNpbU0gPC0gZGF0YS5mcmFtZShzID0gcmVwKHNjZW5hcmlvLCAyMSksIEFTVl9yaWNobmVzcyA9IEFTVnNNLCBLT3NfbWVhbiwgS09zXzk3NSwgS09zXzAyNSkKICByZXR1cm4oc2ltTSkgIAp9CmBgYAoKIyMjIFs2LjJdIFRyaWFsCmBgYHtyfQp0ZXN0X3JhbmRvbU0gPC0gc2ltX2V4dGluY3Rpb25NKHN0YW5kX0FTVl9jb21fYmluYXJpemVkLCBLT19jb21fYmluYXJpemVkLCBzdXJ2X3Byb2IgPSBzdXJ2aXZhbF9yYXRlX21vZCRGMSwgbm9fcmVwZXRpdGlvbiA9IDEwLCBzY2VuYXJpbyA9ICJyYW5kb20iKQoKI0ZvciBLTyByaWNobmVzcyBwbG90Cm1ldGFfcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IHRlc3RfcmFuZG9tTSkgKyBnZW9tX2xpbmUoYWVzKHggPSBBU1ZfcmljaG5lc3MsIHkgPSBLT3NfbWVhbikpCm1ldGFfcGxvdCA8LSBtZXRhX3Bsb3QgKyBnZW9tX3JpYmJvbihhZXMoeCA9IEFTVl9yaWNobmVzcywgeW1pbiA9IEtPc18wMjUsIHltYXggPSBLT3NfOTc1KSwgZmlsbCA9ICJyZWQiLCBhbHBoYSA9IDAuNSkKcGxvdChtZXRhX3Bsb3QpCm1ldGFfcGxvdCA8LSBtZXRhX3Bsb3QgKyBnZW9tX3BvaW50KGRhdGEgPSByaWNobmVzc19NRiwgYWVzKHggPSBBU1ZfcmljaG5lc3MsIHkgPSBNRl9HLCBzaGFwZSA9IHJpY2huZXNzX01GJGxvY2F0aW9uKSwgc2l6ZSA9IDMsIGFscGhhID0gMC45KSArIGxhYnMoc2hhcGUgPSAic2l0ZXMiKSArIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDAsIDEsIDIsIDUsIDYpKSAKcGxvdChtZXRhX3Bsb3QpCgpgYGAKCgojIyMgWzYuM10gUGFyYWxsZWwgY2FsY3VsYXRpb25zIGZvciBtZXRhY29tbXVuaXR5IGV4dGluY3Rpb25zCmBgYHtyfQptZXRhX3NpbSA8LSBtY2xhcHBseSgxOjksIGZ1bmN0aW9uKGkpIHsKICAKICByZXN1bHRfc2ltIDwtIHNpbV9leHRpbmN0aW9uTShzdGFuZF9BU1ZfY29tX2JpbmFyaXplZCwgS09fY29tX2JpbmFyaXplZCwgc3Vydl9wcm9iID0gc3Vydml2YWxfcmF0ZV9tb2RbLCBpXSwgbm9fcmVwZXRpdGlvbiA9IDIwMCwgc2NlbmFyaW8gPSBjb2xuYW1lcyhzdXJ2aXZhbF9yYXRlX21vZClbaV0pCiAgCiAgcmVzdWx0X3NpbQp9LCBtYy5jb3JlcyA9IDkpCmBgYApgYGB7cn0KbWV0YV9zaW0KYGBgCgoKIyMjIFs2LjRdIFZpc3VhbGl6YXRpb24KIyMjIyBbNi40LjFdIENvbXBhcmlzaW9uIG9mIHJlYWxpemVkIGNvbW11bml0aWVzIHdpdGggYSBzaW5nbGUgc2NlbmFyaW8gZnJvbSB0aGUgbWV0YWNvbW11bml0eQpgYGB7cn0KbWV0YV9wbG90X2ogPC0gbGlzdCgpCmZvcihqIGluIDE6OSkgewogIG1ldGFfcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IG1ldGFfc2ltW1tqXV0pICsgZ2VvbV9saW5lKGFlcyh4ID0gQVNWX3JpY2huZXNzLCB5ID0gS09zX21lYW4pKQogIG1ldGFfcGxvdCA8LSBtZXRhX3Bsb3QgKyBnZW9tX3JpYmJvbihhZXMoeCA9IEFTVl9yaWNobmVzcywgeW1pbiA9IEtPc18wMjUsIHltYXggPSBLT3NfOTc1KSwgZmlsbCA9IGosIGFscGhhID0gMC41KQogICNyYW5kb20gcmFuZ2UKICBtZXRhX3Bsb3QgPC0gbWV0YV9wbG90ICsgZ2VvbV9saW5lKGRhdGEgPSBtZXRhX3NpbVtbMV1dLCBhZXMoeCA9IEFTVl9yaWNobmVzcywgeSA9IEtPc18wMjUpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSAKICBtZXRhX3Bsb3QgPC0gbWV0YV9wbG90ICsgZ2VvbV9saW5lKGRhdGEgPSBtZXRhX3NpbVtbMV1dLCBhZXMoeCA9IEFTVl9yaWNobmVzcywgeSA9IEtPc185NzUpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSAKCiAgbWV0YV9wbG90IDwtIG1ldGFfcGxvdCArIGdlb21fcG9pbnQoZGF0YSA9IHJpY2huZXNzX01GLCBhZXMoeCA9IEFTVl9yaWNobmVzcywgeSA9IE1GX0csIHNoYXBlID0gcmljaG5lc3NfTUYkbG9jYXRpb24pLCBzaXplID0gMywgYWxwaGEgPSAwLjkpICsgbGFicyhzaGFwZSA9ICJzaXRlcyIpICsgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMCwgMSwgMiwgNSwgNikpICAgCiAgbWV0YV9wbG90X2pbW2pdXSA8LSBtZXRhX3Bsb3QKfQoKZm9yKGogaW4gMTo5KXsKICBwbG90KG1ldGFfcGxvdF9qW1tqXV0pCn0KCmBgYApGb3IgZ2VuZXJhdGluZyBwZGZzCmBgYHtyfQpmb3IoaiBpbiAyOjUpewogIGZpbGVfbmFtZSA8LSBwYXN0ZSgiZmlndXJlMDVfIiwgai0xLCAiLnBkZiIsIHNlcCA9ICIiKQogIHBkZihmaWxlX25hbWUsIHdpZHRoID0gMTAsIGhlaWdodCA9IDcsIG9uZWZpbGUgPSBGQUxTRSkKICBwbG90KG1ldGFfcGxvdF9qW1tqXV0pCiAgIyBDbG9zZSB0aGUgUG9zdFNjcmlwdCBkZXZpY2UKICBkZXYub2ZmKCkKfQoKZm9yKGogaW4gNjo5KXsKICBmaWxlX25hbWUgPC0gcGFzdGUoImZpZ3VyZVMyXyIsIGotNSwgIi5wZGYiLCBzZXAgPSAiIikKICBwZGYoZmlsZV9uYW1lLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA3LCBvbmVmaWxlID0gRkFMU0UpCiAgcGxvdChtZXRhX3Bsb3Rfaltbal1dKQogICMgQ2xvc2UgdGhlIFBvc3RTY3JpcHQgZGV2aWNlCiAgZGV2Lm9mZigpCn0KCmBgYAoKIyMjIyBbNi40LjJdIEFsbCBzY2VuYXJpb3MgdG9nZXRoZXIKYGBge3J9Cm1ldGFfc2ltX2FsbCA8LSBOVUxMCmZvcihqIGluIDE6OSkgewogIG1ldGFfc2ltX2FsbCA8LSByYmluZC5kYXRhLmZyYW1lKG1ldGFfc2ltX2FsbCwgbWV0YV9zaW1bW2pdXSkKfQoKI3JpYmJvbiBwbG90Cm1ldGFfcGxvdF9hbGwgPC0gZ2dwbG90KGRhdGEgPSBtZXRhX3NpbV9hbGwpICMrIGdlb21fbGluZShhZXMoeCA9IEFTVl9yaWNobmVzcywgeSA9IEtPc19tZWFuLCBncm91cCA9IHMsIGNvbG9yID0gcykpCmZvcihqIGluIDE6NSkgewogIHN0YXJ0IDwtIDEgKyAyMSooaiAtIDEpCiAgZW5kIDwtIDIxKmoKICBtZXRhX3Bsb3RfYWxsIDwtIG1ldGFfcGxvdF9hbGwgKyBnZW9tX3JpYmJvbihkYXRhID0gbWV0YV9zaW1fYWxsW3N0YXJ0OmVuZCwgXSwgYWVzKHggPSBBU1ZfcmljaG5lc3MsIHltaW4gPSBLT3NfMDI1LCB5bWF4ID0gS09zXzk3NSksIGZpbGwgPSBqLCBhbHBoYSA9IDAuNSkKfQptZXRhX3Bsb3RfYWxsIDwtIG1ldGFfcGxvdF9hbGwgKyBnZW9tX3BvaW50KGRhdGEgPSByaWNobmVzc19NRiwgYWVzKHggPSBBU1ZfcmljaG5lc3MsIHkgPSBNRl9HLCBzaGFwZSA9IHJpY2huZXNzX01GJGxvY2F0aW9uKSwgc2l6ZSA9IDMsIGFscGhhID0gMC40KSArIGxhYnMoc2hhcGUgPSAic2l0ZXMiKSArIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDAsIDEsIDIsIDUsIDYpKSAKcGxvdChtZXRhX3Bsb3RfYWxsKQoKI2xpbmUgcGxvdAptZXRhX3Bsb3RfYWxsIDwtIGdncGxvdChkYXRhID0gbWV0YV9zaW1fYWxsKSAjKyBnZW9tX2xpbmUoYWVzKHggPSBBU1ZfcmljaG5lc3MsIHkgPSBLT3NfbWVhbiwgZ3JvdXAgPSBzLCBjb2xvciA9IHMpKQpmb3IoaiBpbiAxOjUpIHsKICBzdGFydCA8LSAxICsgMjEqKGogLSAxKQogIGVuZCA8LSAyMSpqCiAgbWV0YV9wbG90X2FsbCA8LSBtZXRhX3Bsb3RfYWxsICsgZ2VvbV9saW5lKGRhdGEgPSBtZXRhX3NpbV9hbGxbc3RhcnQ6ZW5kLCBdLCBhZXMoeCA9IEFTVl9yaWNobmVzcywgeSA9IEtPc18wMjUpLCBjb2xvciA9IGopCiAgbWV0YV9wbG90X2FsbCA8LSBtZXRhX3Bsb3RfYWxsICsgZ2VvbV9saW5lKGRhdGEgPSBtZXRhX3NpbV9hbGxbc3RhcnQ6ZW5kLCBdLCBhZXMoeCA9IEFTVl9yaWNobmVzcywgeSA9IEtPc185NzUpLCBjb2xvciA9IGopCn0KbWV0YV9wbG90X2FsbCA8LSBtZXRhX3Bsb3RfYWxsICsgZ2VvbV9wb2ludChkYXRhID0gcmljaG5lc3NfTUYsIGFlcyh4ID0gQVNWX3JpY2huZXNzLCB5ID0gTUZfRywgc2hhcGUgPSByaWNobmVzc19NRiRsb2NhdGlvbiksIHNpemUgPSAzLCBhbHBoYSA9IDAuNCkgKyBsYWJzKHNoYXBlID0gInNpdGVzIikgKyBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygwLCAxLCAyLCA1LCA2KSkgCnBsb3QobWV0YV9wbG90X2FsbCkKCmBgYAoKIyMgWzddIEZvciBTdXBwb3J0aW5nIEluZm9ybWF0aW9uCiMjIyBbNy4wXSBDb3JyZWxhdGlvbiBiZXR3ZWVuIGJhY3RlcmlhbCBhYnVuZGFuY2UgYW5kIEFTViByaWNobmVzcwpgYGB7cn0KcGxvdCgKICBkYXRhX3N1bW1hcnkkc3RhbmRfQVNWX3JpY2huZXNzW3NhbXBsZV9JRF0gfiBkYXRhX3N1bW1hcnkkYmFjdGVyaWFsLmFidW5kYW5jZVtzYW1wbGVfSURdLAogIHBjaCA9IGMoMCwxLDIsNSw2KVthcy5mYWN0b3IoZGF0YV9zdW1tYXJ5JGxvY2F0aW9uW3NhbXBsZV9JRF0pXSwKICBjb2wgPSBjKDEsMiwzLDQsNSw2KVthcy5mYWN0b3IoYXR0cmlidXRlc19zYW1wbGUkZGF0ZV9zYW1wbGVbc2FtcGxlX0lEXSldLAogIHhsYWIgPSAiQmFjdGVyaWFsIEFidW5kYW5jZSAoY2VsbHMvbUwpIiwgeWxhYiA9ICJBU1YgcmljaG5lc3MiCikKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9IGxldmVscyhhcy5mYWN0b3IoZGF0YV9zdW1tYXJ5JGxvY2F0aW9uKSksIHBjaCA9IGMoMCwxLDIsNSw2KSkKI2xlZ2VuZCgiYm90dG9tbGVmdCIsIGxlZ2VuZCA9IGxldmVscyhhcy5mYWN0b3IoZGF0YV9zdW1tYXJ5JGRhdGVfc2FtcGxlW3NhbXBsZV9JRF0pKSwgY29sID0gYygxLDIsMyw0LDUsNiksIHBjaCA9IGMoMSwxLDEsMSwxLDEpKQpgYGAKCiMjIyBbNy4xXSBDb3JyZWxhdGlvbiBiZXR3ZWVuIEtPLWJhc2VkIGZ1bmN0aW9uYWwgdHJhaXRzCkNpdGU6IFdoeSBhcmUgc29tZSBtaWNyb2JlcyBtb3JlIHViaXF1aXRvdXMgdGhhbiBvdGhlcnM/IFByZWRpY3RpbmcgdGhlIGhhYml0YXQgYnJlYWR0aCBvZiBzb2lsIGJhY3RlcmlhLCBFY29sb2d5IExldHRlcnMsICgyMDE0KSAxNzogNzk04oCTODAyIGRvaTogMTAuMTExMS9lbGUuMTIyODIKYGBge3J9CnBsb3Qoc3Vydml2YWxfcmF0ZV9tb2QkRjQgfiBzdXJ2aXZhbF9yYXRlX21vZCRGMiwgCiAgICAgeGxhYiA9ICJJbnZlcnNlIG9mIEtPIHJpY2huZXNzIiwKICAgICB5bGFiID0gIkludmVyc2Ugb2YgdGhlIG1lYW4gZGlzc2ltaWxhcml0eSIKICAgICApCgpwbG90KGxvZzEwKHN1cnZpdmFsX3JhdGVfbW9kJEExKSB+IHN1cnZpdmFsX3JhdGVfbW9kJEYxLAogICAgIHhsYWIgPSAiS08gcmljaG5lc3MiLAogICAgIHlsYWIgPSAibG9nMTAobWVhbiBhYnVuZGFuY2UpIgogICAgICkKZjFfYTFfbW9kZWwgPC0gbG0obG9nMTAoQTEpIH4gRjEsIGRhdGEgPSBzdXJ2aXZhbF9yYXRlX21vZCkKc3VtbWFyeShmMV9hMV9tb2RlbCkKYWJsaW5lKGYxX2ExX21vZGVsKQoKcGxvdChzdXJ2aXZhbF9yYXRlX21vZCRBMyB+IHN1cnZpdmFsX3JhdGVfbW9kJEYxLCAKICAgICB4bGFiID0gIktPIHJpY2huZXNzIiwKICAgICB5bGFiID0gIk5vLiBvZiBvY2N1cnJlbmNlIikKCmYxX2EzX21vZGVsIDwtIGxtKEEzIH4gRjEsIGRhdGEgPSBzdXJ2aXZhbF9yYXRlX21vZCkKc3VtbWFyeShmMV9hM19tb2RlbCkKYWJsaW5lKGYxX2EzX21vZGVsKQpwbG90KHN1cnZpdmFsX3JhdGVfbW9kWywgLTFdKQpgYGAKIyMjIFs3LjJdIEFub3RoZXIgbWV0aG9kIHRvIGNhbGN1bGF0ZSBmdW5jdGlvbmFsbHkgdW5pcXVlbmVzcyAKQmFzZWQgb24gdGhlICMgb2YgS09zIHRoYXQgYXJlIG5vdCBzaGFyZWQgd2l0aCBhbGwgb3RoZXIgQVNWcwpgYGB7cn0KdW5pcXVlS08gPC0gbnVtZXJpYyhsZW5ndGgoc3RhbmRfQVNWX2NvbV9iaW5hcml6ZWRbLCAxXSkpCmZvcihqIGluIDE6IGxlbmd0aChzdGFuZF9BU1ZfY29tX2JpbmFyaXplZFssIDFdKSkgewogIHVuaXF1ZUtPW2pdIDwtIHN1bShLT19jb21fYmluYXJpemVkW2osIF0gPT0gMSAmIGFwcGx5KEtPX2NvbV9iaW5hcml6ZWRbLWosIF0sIDIsIHN1bSkgPT0gMCkKfQpgYGAKCmBgYHtyfQpzdW0odW5pcXVlS08gPiAwKQptYXgodW5pcXVlS08pCmBgYAojIyMgWzcuM10gRGlyZWN0IGZpdHRpbmcgb2YgcG93ZXItbGF3IHJlZ3Jlc3Npb24gdG8gdGhlIGFsbCBkYXRhClRoaXMgY291bGQgYmUgZGlyZWN0bHkgY29tcGFyZWQgdG8gRmlnLjMgaW4gUnVobCBldCBhbC4gMjAyMgpgYGB7cn0KZm9yX1NJX21vZGVsIDwtIGxtKGxvZzEwKE1GX0cpIH4gbG9nMTAoQVNWX3JpY2huZXNzKSwgZGF0YSA9IHJpY2huZXNzX01GKQpzdW1tYXJ5KGZvcl9TSV9tb2RlbCkKI2FkZCBkYXRhIGZyb20gcHJlZGljdGlvbiAKcmljaG5lc3NfTUYkYXN2X3JpY2huZXNzMiA9IHNlcSgyMDAsIDMwMDAsIGxlbmd0aC5vdXQgPSAxMykKcmljaG5lc3NfTUYkcHJlZGljdGVkMiA9ICgxMF5mb3JfU0lfbW9kZWwkY29lZmZpY2llbnRzWzFdKSpyaWNobmVzc19NRiRhc3ZfcmljaG5lc3MyXmZvcl9TSV9tb2RlbCRjb2VmZmljaWVudHNbMl0KcG93ZXJfcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IHJpY2huZXNzX01GKSArIGdlb21fcG9pbnQoYWVzKHggPSBBU1ZfcmljaG5lc3MsIHkgPSBNRl9HLCBzaGFwZSA9IHJpY2huZXNzX01GJGxvY2F0aW9uKSwgc2l6ZSA9IDMpICsgbGFicyhzaGFwZSA9ICJzaXRlcyIpICsgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMCwgMSwgMiwgNSwgNikpIApwb3dlcl9wbG90IDwtIHBvd2VyX3Bsb3QgKyBnZW9tX2xpbmUoYWVzKHggPSBhc3ZfcmljaG5lc3MyLCB5ID0gcHJlZGljdGVkMikpCnBsb3QocG93ZXJfcGxvdCkKYGBg